// 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 #include "base/memory/scoped_ptr.h" #include "components/web_modal/native_web_contents_modal_dialog_manager.h" #include "components/web_modal/web_contents_modal_dialog_manager.h" #include "components/web_modal/web_contents_modal_dialog_manager_delegate.h" #include "content/public/browser/notification_details.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/notification_source.h" #include "content/public/browser/notification_types.h" #include "content/public/test/test_renderer_host.h" #include "testing/gtest/include/gtest/gtest.h" namespace web_modal { class TestNativeWebContentsModalDialogManager : public NativeWebContentsModalDialogManager { public: enum DialogState { UNKNOWN, NOT_SHOWN, SHOWN, HIDDEN, CLOSED }; explicit TestNativeWebContentsModalDialogManager( NativeWebContentsModalDialogManagerDelegate* delegate) : delegate_(delegate) {} virtual void ManageDialog(NativeWebContentsModalDialog dialog) OVERRIDE { dialog_state_[dialog] = NOT_SHOWN; } virtual void ShowDialog(NativeWebContentsModalDialog dialog) OVERRIDE { dialog_state_[dialog] = SHOWN; } virtual void HideDialog(NativeWebContentsModalDialog dialog) OVERRIDE { dialog_state_[dialog] = HIDDEN; } virtual void CloseDialog(NativeWebContentsModalDialog dialog) OVERRIDE { delegate_->WillClose(dialog); dialog_state_[dialog] = CLOSED; } virtual void FocusDialog(NativeWebContentsModalDialog dialog) OVERRIDE { } virtual void PulseDialog(NativeWebContentsModalDialog dialog) OVERRIDE { } virtual void HostChanged(WebContentsModalDialogHost* new_host) OVERRIDE { } int GetCloseCount() const { int count = 0; for (DialogStateMap::const_iterator it = dialog_state_.begin(); it != dialog_state_.end(); ++it) { if (it->second == CLOSED) count++; } return count; } DialogState GetDialogState(NativeWebContentsModalDialog dialog) const { DialogStateMap::const_iterator loc = dialog_state_.find(dialog); return loc == dialog_state_.end() ? UNKNOWN : loc->second; } private: typedef std::map DialogStateMap; NativeWebContentsModalDialogManagerDelegate* delegate_; DialogStateMap dialog_state_; DISALLOW_COPY_AND_ASSIGN(TestNativeWebContentsModalDialogManager); }; class TestWebContentsModalDialogManagerDelegate : public WebContentsModalDialogManagerDelegate { public: TestWebContentsModalDialogManagerDelegate() : web_contents_visible_(true), web_contents_blocked_(false) { } // WebContentsModalDialogManagerDelegate overrides virtual void SetWebContentsBlocked(content::WebContents* web_contents, bool blocked) OVERRIDE { web_contents_blocked_ = blocked; } virtual WebContentsModalDialogHost* GetWebContentsModalDialogHost() OVERRIDE { return NULL; } virtual bool IsWebContentsVisible( content::WebContents* web_contents) OVERRIDE { return web_contents_visible_; } void set_web_contents_visible(bool visible) { web_contents_visible_ = visible; } bool web_contents_blocked() const { return web_contents_blocked_; } private: bool web_contents_visible_; bool web_contents_blocked_; DISALLOW_COPY_AND_ASSIGN(TestWebContentsModalDialogManagerDelegate); }; class WebContentsModalDialogManagerTest : public content::RenderViewHostTestHarness { public: WebContentsModalDialogManagerTest() : next_dialog_id(1), manager(NULL), native_manager(NULL) { } virtual void SetUp() { content::RenderViewHostTestHarness::SetUp(); delegate.reset(new TestWebContentsModalDialogManagerDelegate); WebContentsModalDialogManager::CreateForWebContents(web_contents()); manager = WebContentsModalDialogManager::FromWebContents(web_contents()); manager->SetDelegate(delegate.get()); test_api.reset(new WebContentsModalDialogManager::TestApi(manager)); native_manager = new TestNativeWebContentsModalDialogManager(manager); // |manager| owns |native_manager| as a result. test_api->ResetNativeManager(native_manager); } virtual void TearDown() { test_api.reset(); content::RenderViewHostTestHarness::TearDown(); } protected: NativeWebContentsModalDialog MakeFakeDialog() { // WebContentsModalDialogManager treats the NativeWebContentsModalDialog as // an opaque type, so creating fake NativeWebContentsModalDialogs using // reinterpret_cast is valid. return reinterpret_cast(next_dialog_id++); } int next_dialog_id; scoped_ptr delegate; WebContentsModalDialogManager* manager; scoped_ptr test_api; TestNativeWebContentsModalDialogManager* native_manager; DISALLOW_COPY_AND_ASSIGN(WebContentsModalDialogManagerTest); }; NativeWebContentsModalDialogManager* WebContentsModalDialogManager::CreateNativeManager( NativeWebContentsModalDialogManagerDelegate* native_delegate) { return new TestNativeWebContentsModalDialogManager(native_delegate); } // Test that the dialog is shown immediately when the delegate indicates the web // contents is visible. TEST_F(WebContentsModalDialogManagerTest, WebContentsVisible) { // Dialog should be shown while WebContents is visible. const NativeWebContentsModalDialog dialog1 = MakeFakeDialog(); manager->ShowDialog(dialog1); EXPECT_EQ(TestNativeWebContentsModalDialogManager::SHOWN, native_manager->GetDialogState(dialog1)); EXPECT_TRUE(manager->IsShowingDialog()); EXPECT_TRUE(delegate->web_contents_blocked()); } // Test that the dialog is not shown immediately when the delegate indicates the // web contents is not visible. TEST_F(WebContentsModalDialogManagerTest, WebContentsNotVisible) { // Dialog should not be shown while WebContents is not visible. delegate->set_web_contents_visible(false); const NativeWebContentsModalDialog dialog1 = MakeFakeDialog(); manager->ShowDialog(dialog1); EXPECT_EQ(TestNativeWebContentsModalDialogManager::NOT_SHOWN, native_manager->GetDialogState(dialog1)); EXPECT_TRUE(manager->IsShowingDialog()); EXPECT_TRUE(delegate->web_contents_blocked()); } // Test that only the first of multiple dialogs is shown. TEST_F(WebContentsModalDialogManagerTest, ShowDialogs) { const NativeWebContentsModalDialog dialog1 = MakeFakeDialog(); const NativeWebContentsModalDialog dialog2 = MakeFakeDialog(); const NativeWebContentsModalDialog dialog3 = MakeFakeDialog(); manager->ShowDialog(dialog1); manager->ShowDialog(dialog2); manager->ShowDialog(dialog3); EXPECT_TRUE(delegate->web_contents_blocked()); EXPECT_EQ(TestNativeWebContentsModalDialogManager::SHOWN, native_manager->GetDialogState(dialog1)); EXPECT_EQ(TestNativeWebContentsModalDialogManager::NOT_SHOWN, native_manager->GetDialogState(dialog2)); EXPECT_EQ(TestNativeWebContentsModalDialogManager::NOT_SHOWN, native_manager->GetDialogState(dialog3)); } // Test that the dialog is shown/hidden on // NOTIFICATION_WEB_CONTENTS_VISIBILITY_CHANGED. TEST_F(WebContentsModalDialogManagerTest, VisibilityObservation) { const NativeWebContentsModalDialog dialog1 = MakeFakeDialog(); bool web_contents_visible = true; manager->ShowDialog(dialog1); EXPECT_TRUE(manager->IsShowingDialog()); EXPECT_TRUE(delegate->web_contents_blocked()); EXPECT_EQ(TestNativeWebContentsModalDialogManager::SHOWN, native_manager->GetDialogState(dialog1)); web_contents_visible = false; manager->Observe(content::NOTIFICATION_WEB_CONTENTS_VISIBILITY_CHANGED, content::NotificationService::AllSources(), content::Details(&web_contents_visible)); EXPECT_TRUE(manager->IsShowingDialog()); EXPECT_TRUE(delegate->web_contents_blocked()); EXPECT_EQ(TestNativeWebContentsModalDialogManager::HIDDEN, native_manager->GetDialogState(dialog1)); web_contents_visible = true; manager->Observe(content::NOTIFICATION_WEB_CONTENTS_VISIBILITY_CHANGED, content::NotificationService::AllSources(), content::Details(&web_contents_visible)); EXPECT_TRUE(manager->IsShowingDialog()); EXPECT_TRUE(delegate->web_contents_blocked()); EXPECT_EQ(TestNativeWebContentsModalDialogManager::SHOWN, native_manager->GetDialogState(dialog1)); } // Test that the first dialog is always shown, regardless of the order in which // dialogs are closed. TEST_F(WebContentsModalDialogManagerTest, CloseDialogs) { // The front dialog is always shown regardless of dialog close order. const NativeWebContentsModalDialog dialog1 = MakeFakeDialog(); const NativeWebContentsModalDialog dialog2 = MakeFakeDialog(); const NativeWebContentsModalDialog dialog3 = MakeFakeDialog(); const NativeWebContentsModalDialog dialog4 = MakeFakeDialog(); manager->ShowDialog(dialog1); manager->ShowDialog(dialog2); manager->ShowDialog(dialog3); manager->ShowDialog(dialog4); native_manager->CloseDialog(dialog1); EXPECT_TRUE(manager->IsShowingDialog()); EXPECT_TRUE(delegate->web_contents_blocked()); EXPECT_EQ(TestNativeWebContentsModalDialogManager::CLOSED, native_manager->GetDialogState(dialog1)); EXPECT_EQ(TestNativeWebContentsModalDialogManager::SHOWN, native_manager->GetDialogState(dialog2)); EXPECT_EQ(TestNativeWebContentsModalDialogManager::NOT_SHOWN, native_manager->GetDialogState(dialog3)); EXPECT_EQ(TestNativeWebContentsModalDialogManager::NOT_SHOWN, native_manager->GetDialogState(dialog4)); native_manager->CloseDialog(dialog3); EXPECT_TRUE(manager->IsShowingDialog()); EXPECT_TRUE(delegate->web_contents_blocked()); EXPECT_EQ(TestNativeWebContentsModalDialogManager::SHOWN, native_manager->GetDialogState(dialog2)); EXPECT_EQ(TestNativeWebContentsModalDialogManager::CLOSED, native_manager->GetDialogState(dialog3)); EXPECT_EQ(TestNativeWebContentsModalDialogManager::NOT_SHOWN, native_manager->GetDialogState(dialog4)); native_manager->CloseDialog(dialog2); EXPECT_TRUE(manager->IsShowingDialog()); EXPECT_TRUE(delegate->web_contents_blocked()); EXPECT_EQ(TestNativeWebContentsModalDialogManager::CLOSED, native_manager->GetDialogState(dialog2)); EXPECT_EQ(TestNativeWebContentsModalDialogManager::SHOWN, native_manager->GetDialogState(dialog4)); native_manager->CloseDialog(dialog4); EXPECT_FALSE(manager->IsShowingDialog()); EXPECT_FALSE(delegate->web_contents_blocked()); EXPECT_EQ(TestNativeWebContentsModalDialogManager::CLOSED, native_manager->GetDialogState(dialog4)); } // Test that CloseAllDialogs does what it says. TEST_F(WebContentsModalDialogManagerTest, CloseAllDialogs) { const int kWindowCount = 4; for (int i = 0; i < kWindowCount; i++) manager->ShowDialog(MakeFakeDialog()); EXPECT_EQ(0, native_manager->GetCloseCount()); test_api->CloseAllDialogs(); EXPECT_FALSE(delegate->web_contents_blocked()); EXPECT_FALSE(manager->IsShowingDialog()); EXPECT_EQ(kWindowCount, native_manager->GetCloseCount()); } } // namespace web_modal