• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/single_web_contents_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 // Tracks persistent state changes of the native WC-modal dialog manager.
18 class NativeManagerTracker {
19  public:
20   enum DialogState {
21     UNKNOWN,
22     NOT_SHOWN,
23     SHOWN,
24     HIDDEN,
25     CLOSED
26   };
27 
NativeManagerTracker()28   NativeManagerTracker() : state_(UNKNOWN), was_shown_(false) {}
29 
SetState(DialogState state)30   void SetState(DialogState state) {
31     state_ = state;
32     if (state_ == SHOWN)
33       was_shown_ = true;
34   }
35 
36   DialogState state_;
37   bool was_shown_;
38 };
39 
40 NativeManagerTracker unused_tracker;
41 
42 class TestNativeWebContentsModalDialogManager
43     : public SingleWebContentsDialogManager {
44  public:
TestNativeWebContentsModalDialogManager(NativeWebContentsModalDialog dialog,SingleWebContentsDialogManagerDelegate * delegate,NativeManagerTracker * tracker)45   TestNativeWebContentsModalDialogManager(
46       NativeWebContentsModalDialog dialog,
47       SingleWebContentsDialogManagerDelegate* delegate,
48       NativeManagerTracker* tracker)
49       : delegate_(delegate),
50         dialog_(dialog),
51         tracker_(tracker) {
52     if (tracker_)
53       tracker_->SetState(NativeManagerTracker::NOT_SHOWN);
54   }
55 
Show()56   virtual void Show() OVERRIDE {
57     if (tracker_)
58       tracker_->SetState(NativeManagerTracker::SHOWN);
59   }
Hide()60   virtual void Hide() OVERRIDE {
61     if (tracker_)
62       tracker_->SetState(NativeManagerTracker::HIDDEN);
63   }
Close()64   virtual void Close() OVERRIDE {
65     if (tracker_)
66       tracker_->SetState(NativeManagerTracker::CLOSED);
67     delegate_->WillClose(dialog_);
68   }
Focus()69   virtual void Focus() OVERRIDE {
70   }
Pulse()71   virtual void Pulse() OVERRIDE {
72   }
HostChanged(WebContentsModalDialogHost * new_host)73   virtual void HostChanged(WebContentsModalDialogHost* new_host) OVERRIDE {
74   }
dialog()75   virtual NativeWebContentsModalDialog dialog() OVERRIDE {
76       return dialog_;
77   }
78 
StopTracking()79   void StopTracking() {
80     tracker_ = NULL;
81   }
82 
83  private:
84   SingleWebContentsDialogManagerDelegate* delegate_;
85   NativeWebContentsModalDialog dialog_;
86   NativeManagerTracker* tracker_;
87 
88   DISALLOW_COPY_AND_ASSIGN(TestNativeWebContentsModalDialogManager);
89 };
90 
91 class WebContentsModalDialogManagerTest
92     : public content::RenderViewHostTestHarness {
93  public:
WebContentsModalDialogManagerTest()94   WebContentsModalDialogManagerTest()
95       : next_dialog_id(1),
96         manager(NULL) {
97   }
98 
SetUp()99   virtual void SetUp() {
100     content::RenderViewHostTestHarness::SetUp();
101 
102     delegate.reset(new TestWebContentsModalDialogManagerDelegate);
103     WebContentsModalDialogManager::CreateForWebContents(web_contents());
104     manager = WebContentsModalDialogManager::FromWebContents(web_contents());
105     manager->SetDelegate(delegate.get());
106     test_api.reset(new WebContentsModalDialogManager::TestApi(manager));
107   }
108 
TearDown()109   virtual void TearDown() {
110     test_api.reset();
111     content::RenderViewHostTestHarness::TearDown();
112   }
113 
114  protected:
MakeFakeDialog()115   NativeWebContentsModalDialog MakeFakeDialog() {
116     // WebContentsModalDialogManager treats the NativeWebContentsModalDialog as
117     // an opaque type, so creating fake NativeWebContentsModalDialogs using
118     // reinterpret_cast is valid.
119     return reinterpret_cast<NativeWebContentsModalDialog>(next_dialog_id++);
120   }
121 
122   int next_dialog_id;
123   scoped_ptr<TestWebContentsModalDialogManagerDelegate> delegate;
124   WebContentsModalDialogManager* manager;
125   scoped_ptr<WebContentsModalDialogManager::TestApi> test_api;
126 
127   DISALLOW_COPY_AND_ASSIGN(WebContentsModalDialogManagerTest);
128 };
129 
130 SingleWebContentsDialogManager*
CreateNativeWebModalManager(NativeWebContentsModalDialog dialog,SingleWebContentsDialogManagerDelegate * native_delegate)131 WebContentsModalDialogManager::CreateNativeWebModalManager(
132     NativeWebContentsModalDialog dialog,
133     SingleWebContentsDialogManagerDelegate* native_delegate) {
134   NOTREACHED();
135   return new TestNativeWebContentsModalDialogManager(
136       dialog,
137       native_delegate,
138       &unused_tracker);
139 }
140 
141 // Test that the dialog is shown immediately when the delegate indicates the web
142 // contents is visible.
TEST_F(WebContentsModalDialogManagerTest,WebContentsVisible)143 TEST_F(WebContentsModalDialogManagerTest, WebContentsVisible) {
144   // Dialog should be shown while WebContents is visible.
145   const NativeWebContentsModalDialog dialog = MakeFakeDialog();
146 
147   NativeManagerTracker tracker;
148   TestNativeWebContentsModalDialogManager* native_manager =
149       new TestNativeWebContentsModalDialogManager(dialog, manager, &tracker);
150   manager->ShowDialogWithManager(dialog,
151       scoped_ptr<SingleWebContentsDialogManager>(native_manager).Pass());
152 
153   EXPECT_EQ(NativeManagerTracker::SHOWN, tracker.state_);
154   EXPECT_TRUE(manager->IsDialogActive());
155   EXPECT_TRUE(delegate->web_contents_blocked());
156   EXPECT_TRUE(tracker.was_shown_);
157 
158   native_manager->StopTracking();
159 }
160 
161 // Test that the dialog is not shown immediately when the delegate indicates the
162 // web contents is not visible.
TEST_F(WebContentsModalDialogManagerTest,WebContentsNotVisible)163 TEST_F(WebContentsModalDialogManagerTest, WebContentsNotVisible) {
164   // Dialog should not be shown while WebContents is not visible.
165   delegate->set_web_contents_visible(false);
166 
167   const NativeWebContentsModalDialog dialog = MakeFakeDialog();
168 
169   NativeManagerTracker tracker;
170   TestNativeWebContentsModalDialogManager* native_manager =
171       new TestNativeWebContentsModalDialogManager(dialog, manager, &tracker);
172   manager->ShowDialogWithManager(dialog,
173       scoped_ptr<SingleWebContentsDialogManager>(native_manager).Pass());
174 
175   EXPECT_EQ(NativeManagerTracker::NOT_SHOWN, tracker.state_);
176   EXPECT_TRUE(manager->IsDialogActive());
177   EXPECT_TRUE(delegate->web_contents_blocked());
178   EXPECT_FALSE(tracker.was_shown_);
179 
180   native_manager->StopTracking();
181 }
182 
183 // Test that only the first of multiple dialogs is shown.
TEST_F(WebContentsModalDialogManagerTest,ShowDialogs)184 TEST_F(WebContentsModalDialogManagerTest, ShowDialogs) {
185   const NativeWebContentsModalDialog dialog1 = MakeFakeDialog();
186   const NativeWebContentsModalDialog dialog2 = MakeFakeDialog();
187   const NativeWebContentsModalDialog dialog3 = MakeFakeDialog();
188 
189   NativeManagerTracker tracker1;
190   NativeManagerTracker tracker2;
191   NativeManagerTracker tracker3;
192   TestNativeWebContentsModalDialogManager* native_manager1 =
193       new TestNativeWebContentsModalDialogManager(dialog1, manager, &tracker1);
194   TestNativeWebContentsModalDialogManager* native_manager2 =
195       new TestNativeWebContentsModalDialogManager(dialog2, manager, &tracker2);
196   TestNativeWebContentsModalDialogManager* native_manager3 =
197       new TestNativeWebContentsModalDialogManager(dialog3, manager, &tracker3);
198   manager->ShowDialogWithManager(dialog1,
199       scoped_ptr<SingleWebContentsDialogManager>(native_manager1).Pass());
200   manager->ShowDialogWithManager(dialog2,
201       scoped_ptr<SingleWebContentsDialogManager>(native_manager2).Pass());
202   manager->ShowDialogWithManager(dialog3,
203       scoped_ptr<SingleWebContentsDialogManager>(native_manager3).Pass());
204 
205   EXPECT_TRUE(delegate->web_contents_blocked());
206   EXPECT_EQ(NativeManagerTracker::SHOWN, tracker1.state_);
207   EXPECT_EQ(NativeManagerTracker::NOT_SHOWN, tracker2.state_);
208   EXPECT_EQ(NativeManagerTracker::NOT_SHOWN, tracker3.state_);
209 
210   native_manager1->StopTracking();
211   native_manager2->StopTracking();
212   native_manager3->StopTracking();
213 }
214 
215 // Test that the dialog is shown/hidden when the WebContents is shown/hidden.
TEST_F(WebContentsModalDialogManagerTest,VisibilityObservation)216 TEST_F(WebContentsModalDialogManagerTest, VisibilityObservation) {
217   const NativeWebContentsModalDialog dialog = MakeFakeDialog();
218 
219   NativeManagerTracker tracker;
220   TestNativeWebContentsModalDialogManager* native_manager =
221       new TestNativeWebContentsModalDialogManager(dialog, manager, &tracker);
222   manager->ShowDialogWithManager(dialog,
223       scoped_ptr<SingleWebContentsDialogManager>(native_manager).Pass());
224 
225   EXPECT_TRUE(manager->IsDialogActive());
226   EXPECT_TRUE(delegate->web_contents_blocked());
227   EXPECT_EQ(NativeManagerTracker::SHOWN, tracker.state_);
228 
229   test_api->WebContentsWasHidden();
230 
231   EXPECT_TRUE(manager->IsDialogActive());
232   EXPECT_TRUE(delegate->web_contents_blocked());
233   EXPECT_EQ(NativeManagerTracker::HIDDEN, tracker.state_);
234 
235   test_api->WebContentsWasShown();
236 
237   EXPECT_TRUE(manager->IsDialogActive());
238   EXPECT_TRUE(delegate->web_contents_blocked());
239   EXPECT_EQ(NativeManagerTracker::SHOWN, tracker.state_);
240 
241   native_manager->StopTracking();
242 }
243 
244 // Test that attaching an interstitial page closes all dialogs.
TEST_F(WebContentsModalDialogManagerTest,InterstitialPage)245 TEST_F(WebContentsModalDialogManagerTest, InterstitialPage) {
246   const NativeWebContentsModalDialog dialog1 = MakeFakeDialog();
247   const NativeWebContentsModalDialog dialog2 = MakeFakeDialog();
248 
249   NativeManagerTracker tracker1;
250   NativeManagerTracker tracker2;
251   TestNativeWebContentsModalDialogManager* native_manager1 =
252       new TestNativeWebContentsModalDialogManager(dialog1, manager, &tracker1);
253   TestNativeWebContentsModalDialogManager* native_manager2 =
254       new TestNativeWebContentsModalDialogManager(dialog2, manager, &tracker2);
255   manager->ShowDialogWithManager(dialog1,
256       scoped_ptr<SingleWebContentsDialogManager>(native_manager1).Pass());
257   manager->ShowDialogWithManager(dialog2,
258       scoped_ptr<SingleWebContentsDialogManager>(native_manager2).Pass());
259 
260   test_api->DidAttachInterstitialPage();
261 
262 #if defined(USE_AURA)
263   EXPECT_EQ(NativeManagerTracker::CLOSED, tracker1.state_);
264   EXPECT_EQ(NativeManagerTracker::CLOSED, tracker2.state_);
265 #else
266   EXPECT_EQ(NativeManagerTracker::SHOWN, tracker1.state_);
267   EXPECT_EQ(NativeManagerTracker::NOT_SHOWN, tracker2.state_);
268 #endif
269 
270   EXPECT_TRUE(tracker1.was_shown_);
271   EXPECT_FALSE(tracker2.was_shown_);
272 
273 #if !defined(USE_AURA)
274   native_manager1->StopTracking();
275   native_manager2->StopTracking();
276 #endif
277 }
278 
279 
280 // Test that the first dialog is always shown, regardless of the order in which
281 // dialogs are closed.
TEST_F(WebContentsModalDialogManagerTest,CloseDialogs)282 TEST_F(WebContentsModalDialogManagerTest, CloseDialogs) {
283   // The front dialog is always shown regardless of dialog close order.
284   const NativeWebContentsModalDialog dialog1 = MakeFakeDialog();
285   const NativeWebContentsModalDialog dialog2 = MakeFakeDialog();
286   const NativeWebContentsModalDialog dialog3 = MakeFakeDialog();
287   const NativeWebContentsModalDialog dialog4 = MakeFakeDialog();
288 
289   NativeManagerTracker tracker1;
290   NativeManagerTracker tracker2;
291   NativeManagerTracker tracker3;
292   NativeManagerTracker tracker4;
293   TestNativeWebContentsModalDialogManager* native_manager1 =
294       new TestNativeWebContentsModalDialogManager(dialog1, manager, &tracker1);
295   TestNativeWebContentsModalDialogManager* native_manager2 =
296       new TestNativeWebContentsModalDialogManager(dialog2, manager, &tracker2);
297   TestNativeWebContentsModalDialogManager* native_manager3 =
298       new TestNativeWebContentsModalDialogManager(dialog3, manager, &tracker3);
299   TestNativeWebContentsModalDialogManager* native_manager4 =
300       new TestNativeWebContentsModalDialogManager(dialog4, manager, &tracker4);
301   manager->ShowDialogWithManager(dialog1,
302       scoped_ptr<SingleWebContentsDialogManager>(native_manager1).Pass());
303   manager->ShowDialogWithManager(dialog2,
304       scoped_ptr<SingleWebContentsDialogManager>(native_manager2).Pass());
305   manager->ShowDialogWithManager(dialog3,
306       scoped_ptr<SingleWebContentsDialogManager>(native_manager3).Pass());
307   manager->ShowDialogWithManager(dialog4,
308       scoped_ptr<SingleWebContentsDialogManager>(native_manager4).Pass());
309 
310   native_manager1->Close();
311 
312   EXPECT_TRUE(manager->IsDialogActive());
313   EXPECT_TRUE(delegate->web_contents_blocked());
314   EXPECT_EQ(NativeManagerTracker::CLOSED, tracker1.state_);
315   EXPECT_EQ(NativeManagerTracker::SHOWN, tracker2.state_);
316   EXPECT_EQ(NativeManagerTracker::NOT_SHOWN, tracker3.state_);
317   EXPECT_EQ(NativeManagerTracker::NOT_SHOWN, tracker4.state_);
318 
319   native_manager3->Close();
320 
321   EXPECT_TRUE(manager->IsDialogActive());
322   EXPECT_TRUE(delegate->web_contents_blocked());
323   EXPECT_EQ(NativeManagerTracker::CLOSED, tracker1.state_);
324   EXPECT_EQ(NativeManagerTracker::SHOWN, tracker2.state_);
325   EXPECT_EQ(NativeManagerTracker::CLOSED, tracker3.state_);
326   EXPECT_EQ(NativeManagerTracker::NOT_SHOWN, tracker4.state_);
327   EXPECT_FALSE(tracker3.was_shown_);
328 
329   native_manager2->Close();
330 
331   EXPECT_TRUE(manager->IsDialogActive());
332   EXPECT_TRUE(delegate->web_contents_blocked());
333   EXPECT_EQ(NativeManagerTracker::CLOSED, tracker1.state_);
334   EXPECT_EQ(NativeManagerTracker::CLOSED, tracker2.state_);
335   EXPECT_EQ(NativeManagerTracker::CLOSED, tracker3.state_);
336   EXPECT_EQ(NativeManagerTracker::SHOWN, tracker4.state_);
337   EXPECT_FALSE(tracker3.was_shown_);
338 
339   native_manager4->Close();
340 
341   EXPECT_FALSE(manager->IsDialogActive());
342   EXPECT_FALSE(delegate->web_contents_blocked());
343   EXPECT_EQ(NativeManagerTracker::CLOSED, tracker1.state_);
344   EXPECT_EQ(NativeManagerTracker::CLOSED, tracker2.state_);
345   EXPECT_EQ(NativeManagerTracker::CLOSED, tracker3.state_);
346   EXPECT_EQ(NativeManagerTracker::CLOSED, tracker4.state_);
347   EXPECT_TRUE(tracker1.was_shown_);
348   EXPECT_TRUE(tracker2.was_shown_);
349   EXPECT_FALSE(tracker3.was_shown_);
350   EXPECT_TRUE(tracker4.was_shown_);
351 }
352 
353 // Test that CloseAllDialogs does what it says.
TEST_F(WebContentsModalDialogManagerTest,CloseAllDialogs)354 TEST_F(WebContentsModalDialogManagerTest, CloseAllDialogs) {
355   const int kWindowCount = 4;
356   NativeManagerTracker trackers[kWindowCount];
357   TestNativeWebContentsModalDialogManager* native_managers[kWindowCount];
358   for (int i = 0; i < kWindowCount; i++) {
359     const NativeWebContentsModalDialog dialog = MakeFakeDialog();
360     native_managers[i] =
361         new TestNativeWebContentsModalDialogManager(
362             dialog, manager, &(trackers[i]));
363     manager->ShowDialogWithManager(dialog,
364     scoped_ptr<SingleWebContentsDialogManager>(
365         native_managers[i]).Pass());
366   }
367 
368   for (int i = 0; i < kWindowCount; i++)
369     EXPECT_NE(NativeManagerTracker::CLOSED, trackers[i].state_);
370 
371   test_api->CloseAllDialogs();
372 
373   EXPECT_FALSE(delegate->web_contents_blocked());
374   EXPECT_FALSE(manager->IsDialogActive());
375   for (int i = 0; i < kWindowCount; i++)
376     EXPECT_EQ(NativeManagerTracker::CLOSED, trackers[i].state_);
377 }
378 
379 }  // namespace web_modal
380