diff options
author | mad@google.com <mad@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-11-17 17:50:11 +0000 |
---|---|---|
committer | mad@google.com <mad@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-11-17 17:50:11 +0000 |
commit | a66464ec0d01381ed75f8514076c75c8d30d9ddd (patch) | |
tree | 35160e2cd62c73ee9441e8cbbed53726472e24f2 /ceee/ie/plugin | |
parent | f65e1af922ff4178abcc0566be137c23793bd9c3 (diff) | |
download | chromium_src-a66464ec0d01381ed75f8514076c75c8d30d9ddd.zip chromium_src-a66464ec0d01381ed75f8514076c75c8d30d9ddd.tar.gz chromium_src-a66464ec0d01381ed75f8514076c75c8d30d9ddd.tar.bz2 |
Committing for Vadim:
http://codereview.chromium.org/4991002/
New unittests for infobar.
BUG=None
TEST=None
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@66459 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ceee/ie/plugin')
-rw-r--r-- | ceee/ie/plugin/bho/executor_unittest.cc | 68 | ||||
-rw-r--r-- | ceee/ie/plugin/bho/infobar_manager.cc | 65 | ||||
-rw-r--r-- | ceee/ie/plugin/bho/infobar_manager.h | 26 | ||||
-rw-r--r-- | ceee/ie/plugin/bho/infobar_manager_unittest.cc | 203 | ||||
-rw-r--r-- | ceee/ie/plugin/bho/infobar_window.cc | 13 | ||||
-rw-r--r-- | ceee/ie/plugin/bho/infobar_window.h | 15 | ||||
-rw-r--r-- | ceee/ie/plugin/bho/infobar_window_unittest.cc | 181 |
7 files changed, 535 insertions, 36 deletions
diff --git a/ceee/ie/plugin/bho/executor_unittest.cc b/ceee/ie/plugin/bho/executor_unittest.cc index d68f2d0..f18736d 100644 --- a/ceee/ie/plugin/bho/executor_unittest.cc +++ b/ceee/ie/plugin/bho/executor_unittest.cc @@ -19,6 +19,7 @@ #include "ceee/ie/common/ie_util.h" #include "ceee/ie/common/mock_ie_tab_interfaces.h" #include "ceee/ie/plugin/bho/executor.h" +#include "ceee/ie/plugin/bho/infobar_manager.h" #include "ceee/ie/testing/mock_broker_and_friends.h" #include "ceee/ie/testing/mock_frame_event_handler_host.h" #include "ceee/common/initializing_coclass.h" @@ -80,6 +81,15 @@ class TestingMockExecutorCreatorTeardown MOCK_METHOD1_WITH_CALLTYPE(__stdcall, Teardown, HRESULT(long)); }; +class MockInfobarManager : public infobar_api::InfobarManager { + public: + MockInfobarManager() : InfobarManager(kGoodWindow) {} + MOCK_METHOD4(Show, HRESULT(infobar_api::InfobarType, int, + const std::wstring&, bool)); + MOCK_METHOD1(Hide, HRESULT(infobar_api::InfobarType)); + MOCK_METHOD0(HideAll, void()); +}; + TEST(ExecutorCreator, ProperTearDownOnDestruction) { StrictMock<TestingMockExecutorCreatorTeardown>* executor_creator = NULL; CComPtr<ICeeeExecutorCreator> executor_creator_keeper; @@ -315,6 +325,14 @@ class TestingExecutor void set_id(HWND hwnd) { hwnd_ = hwnd; } + void InitializeInfobarManager(MockInfobarManager** manager) { + ASSERT_TRUE(manager != NULL); + *manager = new MockInfobarManager(); + infobar_manager_.reset(*manager); + } + void TerminateInfobarManager() { + infobar_manager_.reset(NULL); + } static BOOL MockEnumChildWindows(HWND, WNDENUMPROC, LPARAM p) { std::vector<HWND>* tab_windows = reinterpret_cast<std::vector<HWND>*>(p); *tab_windows = tab_windows_; @@ -1083,6 +1101,54 @@ TEST_F(ExecutorTests, RegisterCookieStore) { EXPECT_EQ(S_OK, executor_->CookieStoreIsRegistered()); } -// TODO(vadimb@google.com): Add unit tests for infobar APIs. +TEST_F(ExecutorTests, ShowInfobar) { + testing::LogDisabler no_dchecks; + CComBSTR url(L"/infobar/test.html"); + CComBSTR empty_url(L""); + CComBSTR extension_id(L"abcdefjh"); + + // Calling when manager has not been initialized. + EXPECT_HRESULT_FAILED(executor_->ShowInfobar(url, NULL)); + + // Initializing the manager and calling it with different parameters. + MockInfobarManager* manager; + executor_->InitializeInfobarManager(&manager); + + EXPECT_CALL(*manager, Show(infobar_api::TOP_INFOBAR, _, + std::wstring(url.m_str), true)). + WillOnce(Return(S_OK)); + EXPECT_CALL(mock_window_utils_, GetTopLevelParent(_)). + WillRepeatedly(Return(kGoodWindow)); + CeeeWindowHandle window_handle; + + EXPECT_HRESULT_SUCCEEDED(executor_->ShowInfobar(url, &window_handle)); + EXPECT_EQ(reinterpret_cast<CeeeWindowHandle>(kGoodWindow), window_handle); + + EXPECT_CALL(*manager, HideAll()).Times(1); + EXPECT_HRESULT_SUCCEEDED(executor_->ShowInfobar(empty_url, &window_handle)); + EXPECT_EQ(0, window_handle); + + EXPECT_CALL(*manager, Show(infobar_api::TOP_INFOBAR, _, + std::wstring(url.m_str), true)). + WillOnce(Return(E_FAIL)); + EXPECT_HRESULT_FAILED(executor_->ShowInfobar(url, &window_handle)); + EXPECT_EQ(0, window_handle); + + EXPECT_CALL(*manager, HideAll()).Times(1); + EXPECT_HRESULT_SUCCEEDED(executor_->OnTopFrameBeforeNavigate(url)); + + EXPECT_HRESULT_SUCCEEDED(executor_->SetExtensionId(extension_id)); + std::wstring full_url(L"chrome-extension://"); + full_url += extension_id.m_str; + full_url += url.m_str; + EXPECT_CALL(*manager, Show(infobar_api::TOP_INFOBAR, _, full_url, true)). + WillOnce(Return(S_OK)); + EXPECT_HRESULT_SUCCEEDED(executor_->ShowInfobar(url, &window_handle)); + + // Have to destroy the manager before LogDisabler from this test goes out of + // scope. + EXPECT_CALL(user32_, IsWindow(NULL)).WillRepeatedly(Return(FALSE)); + executor_->TerminateInfobarManager(); +} } // namespace diff --git a/ceee/ie/plugin/bho/infobar_manager.cc b/ceee/ie/plugin/bho/infobar_manager.cc index 6b969f6..30ff9a9 100644 --- a/ceee/ie/plugin/bho/infobar_manager.cc +++ b/ceee/ie/plugin/bho/infobar_manager.cc @@ -31,7 +31,9 @@ namespace infobar_api { // WM_NCCALCSIZE to resize its client area. It also handles WM_SIZE and WM_MOVE // messages to make infobars consistent with IE content window's size and // position. -class InfobarManager::ContainerWindow : public CWindowImpl<ContainerWindow> { +class InfobarManager::ContainerWindow + : public InfobarManager::ContainerWindowInterface, + public CWindowImpl<ContainerWindow> { public: ContainerWindow(HWND container, InfobarManager* manager) : infobar_manager_(manager) { @@ -44,10 +46,18 @@ class InfobarManager::ContainerWindow : public CWindowImpl<ContainerWindow> { UnsubclassWindow(); } - bool destroyed() const { + virtual bool IsDestroyed() const { return destroyed_; } + virtual HWND GetWindowHandle() const { + return IsWindow() ? m_hWnd : NULL; + } + + virtual bool PostWindowsMessage(UINT msg, WPARAM wparam, LPARAM lparam) { + return PostMessage(msg, wparam, lparam) != 0; + } + BEGIN_MSG_MAP_EX(ContainerWindow) MSG_WM_NCCALCSIZE(OnNcCalcSize) MSG_WM_SIZE(OnSize) @@ -135,17 +145,11 @@ class InfobarManager::ContainerWindow : public CWindowImpl<ContainerWindow> { InfobarManager::InfobarManager(HWND tab_window) : tab_window_(tab_window) { - for (int index = 0; index < END_OF_INFOBAR_TYPE; ++index) { - // Note that when InfobarManager is being initialized the IE has not created - // the tab. Therefore we cannot find the container window here and have to - // pass interface for a function that finds windows to be called later. - infobars_[index].reset( - InfobarWindow::CreateInfobar(static_cast<InfobarType>(index), this)); - } } HRESULT InfobarManager::Show(InfobarType type, int max_height, const std::wstring& url, bool slide) { + LazyInitialize(type); if (type < FIRST_INFOBAR_TYPE || type >= END_OF_INFOBAR_TYPE || infobars_[type] == NULL) { return E_INVALIDARG; @@ -155,8 +159,7 @@ HRESULT InfobarManager::Show(InfobarType type, int max_height, infobars_[type]->Navigate(url); // Create the window if not created. if (!infobars_[type]->IsWindow()) { - infobars_[type]->Create(tab_window_, NULL, NULL, - WS_CHILD | WS_CLIPCHILDREN); + infobars_[type]->InternalCreate(tab_window_, WS_CHILD | WS_CLIPCHILDREN); } if (!infobars_[type]->IsWindow()) return E_UNEXPECTED; @@ -166,10 +169,12 @@ HRESULT InfobarManager::Show(InfobarType type, int max_height, } HRESULT InfobarManager::Hide(InfobarType type) { - if (type < FIRST_INFOBAR_TYPE || type >= END_OF_INFOBAR_TYPE || - infobars_[type] == NULL) { + if (type < FIRST_INFOBAR_TYPE || type >= END_OF_INFOBAR_TYPE) return E_INVALIDARG; - } + // No lazy initialization here - if the infobar has not been created just + // return; + if (infobars_[type] == NULL) + return E_UNEXPECTED; // There is a choice either to hide or to destroy the infobar window. // This implementation destroys the infobar to save resources and stop all // scripts that possibly still run in the window. If we want to just hide the @@ -208,7 +213,7 @@ static BOOL CALLBACK FindContentParentWindowsProc(HWND hwnd, LPARAM lparam) { } HWND InfobarManager::GetContainerWindow() { - if (container_window_ != NULL && container_window_->destroyed()) + if (container_window_ != NULL && container_window_->IsDestroyed()) container_window_.reset(NULL); if (container_window_ == NULL) { @@ -221,12 +226,13 @@ HWND InfobarManager::GetContainerWindow() { DCHECK(content_parent_window); if (content_parent_window != NULL) { container_window_.reset( - new ContainerWindow(content_parent_window, this)); + CreateContainerWindow(content_parent_window, this)); } } } - DCHECK(container_window_ != NULL && container_window_->IsWindow()); - return container_window_->m_hWnd; + DCHECK(container_window_ != NULL && + container_window_->GetWindowHandle() != NULL); + return container_window_->GetWindowHandle(); } void InfobarManager::OnWindowClose(InfobarType type) { @@ -234,8 +240,8 @@ void InfobarManager::OnWindowClose(InfobarType type) { // infobar window right away as it may result on deleting the object that // started this callback. So instead we post ourtselves the message. if (container_window_ != NULL) - container_window_->PostMessage(TM_DELAYED_CLOSE_INFOBAR, - static_cast<WPARAM>(type), 0); + container_window_->PostWindowsMessage(TM_DELAYED_CLOSE_INFOBAR, + static_cast<WPARAM>(type), 0); } void InfobarManager::OnContainerWindowNcCalcSize(RECT* rect) { @@ -267,4 +273,23 @@ void InfobarManager::OnContainerWindowDestroy() { } } +void InfobarManager::LazyInitialize(InfobarType type) { + DCHECK(type >= FIRST_INFOBAR_TYPE && type < END_OF_INFOBAR_TYPE); + if (type < FIRST_INFOBAR_TYPE || type >= END_OF_INFOBAR_TYPE) + return; + + if (infobars_[type] != NULL) + return; + + // Note that when InfobarManager is being initialized the IE has not created + // the tab. Therefore we cannot find the container window here and have to + // pass interface for a function that finds windows to be called later. + infobars_[type].reset(InfobarWindow::CreateInfobar(type, this)); +} + +InfobarManager::ContainerWindowInterface* InfobarManager::CreateContainerWindow( + HWND container, InfobarManager* manager) { + return new ContainerWindow(container, manager); +} + } // namespace infobar_api diff --git a/ceee/ie/plugin/bho/infobar_manager.h b/ceee/ie/plugin/bho/infobar_manager.h index dead924..d09e3d9 100644 --- a/ceee/ie/plugin/bho/infobar_manager.h +++ b/ceee/ie/plugin/bho/infobar_manager.h @@ -24,12 +24,12 @@ class InfobarManager : public InfobarWindow::Delegate, // Shows the infobar of the specified type and navigates it to the specified // URL. - HRESULT Show(InfobarType type, int max_height, const std::wstring& url, - bool slide); + virtual HRESULT Show(InfobarType type, int max_height, + const std::wstring& url, bool slide); // Hides the infobar of the specified type. - HRESULT Hide(InfobarType type); + virtual HRESULT Hide(InfobarType type); // Hides all infobars. - void HideAll(); + virtual void HideAll(); // Implementation of InfobarWindow::Delegate. // Finds the handle of the container window. @@ -37,14 +37,28 @@ class InfobarManager : public InfobarWindow::Delegate, // Informs about window.close() event. virtual void OnWindowClose(InfobarType type); - private: + protected: class ContainerWindow; + class ContainerWindowInterface { + public: + virtual ~ContainerWindowInterface() {} + virtual bool IsDestroyed() const = 0; + virtual HWND GetWindowHandle() const = 0; + virtual bool PostWindowsMessage(UINT msg, WPARAM wparam, LPARAM lparam) = 0; + }; + + // Lazy initialization of InfobarWindow object. + void LazyInitialize(InfobarType type); + + // Creates container window. Separated for the unit testing. + virtual ContainerWindowInterface* CreateContainerWindow( + HWND container, InfobarManager* manager); // The HWND of the tab window the infobars are associated with. HWND tab_window_; // Parent window for IE content window. - scoped_ptr<ContainerWindow> container_window_; + scoped_ptr<ContainerWindowInterface> container_window_; // Infobar windows. scoped_ptr<InfobarWindow> infobars_[END_OF_INFOBAR_TYPE]; diff --git a/ceee/ie/plugin/bho/infobar_manager_unittest.cc b/ceee/ie/plugin/bho/infobar_manager_unittest.cc new file mode 100644 index 0000000..610634e --- /dev/null +++ b/ceee/ie/plugin/bho/infobar_manager_unittest.cc @@ -0,0 +1,203 @@ +// Copyright (c) 2010 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. +// +// Infobar manager implementation unit tests. + +// MockWin32 must not be included after atlwin, which is included by some +// headers in here, so we need to put it at the top: +#include "ceee/testing/utils/mock_win32.h" // NOLINT + +#include "ceee/ie/plugin/bho/infobar_manager.h" +#include "ceee/ie/plugin/bho/infobar_window.h" +#include "ceee/testing/utils/instance_count_mixin.h" +#include "ceee/testing/utils/test_utils.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +#include "broker_lib.h" // NOLINT + +namespace { + +using testing::_; +using testing::Invoke; +using testing::InvokeWithoutArgs; +using testing::NotNull; +using testing::Return; +using testing::SetArgumentPointee; +using testing::StrictMock; + +const HWND kGoodWindow = reinterpret_cast<HWND>(42); +const HWND kParentWindow = reinterpret_cast<HWND>(77); +const HWND kInfobarWindow = reinterpret_cast<HWND>(91); +const wchar_t* kUrl1 = L"/infobar/test.html"; +const int kMaxHeight = 55; + +class MockInfobarDelegate : public infobar_api::InfobarWindow::Delegate { + public: + MOCK_METHOD0(GetContainerWindow, HWND()); + MOCK_METHOD1(OnWindowClose, void(infobar_api::InfobarType)); +}; + +class MockInfobarWindow : public infobar_api::InfobarWindow { + public: + MockInfobarWindow(infobar_api::InfobarType type, Delegate* delegate) + : infobar_api::InfobarWindow(type, delegate) {} + MOCK_METHOD2(InternalCreate, HWND(HWND, DWORD)); + MOCK_METHOD2(Show, HRESULT(int, bool)); + MOCK_METHOD0(Hide, HRESULT()); + MOCK_METHOD1(Navigate, HRESULT(const std::wstring& url)); + MOCK_METHOD0(Reset, void()); + + HWND SetInfobarHwnd() { + m_hWnd = kInfobarWindow; + return m_hWnd; + } +}; + +class TestingInfobarManager : public infobar_api::InfobarManager { + public: + class MockContainerWindow : public ContainerWindowInterface { + public: + // TODO(vadimb@google.com): Mock these two methods and test different + // behaviors when they return different values. + virtual bool IsDestroyed() const { return false; } + virtual HWND GetWindowHandle() const { return kParentWindow; } + MOCK_METHOD3(PostWindowsMessage, bool(UINT, WPARAM, LPARAM)); + }; + + explicit TestingInfobarManager(HWND tab_window) + : infobar_api::InfobarManager(tab_window) { + } + + MockInfobarWindow* GetInfobarWindow(infobar_api::InfobarType type) { + if (type < infobar_api::FIRST_INFOBAR_TYPE || + type >= infobar_api::END_OF_INFOBAR_TYPE) { + return NULL; + } + return reinterpret_cast<MockInfobarWindow*>(infobars_[type].get()); + } + + void InitInfobarWindow(infobar_api::InfobarType type, Delegate* delegate) { + ASSERT_TRUE(type >= infobar_api::FIRST_INFOBAR_TYPE && + type < infobar_api::END_OF_INFOBAR_TYPE); + ASSERT_TRUE(infobars_[type] == NULL); + infobars_[type].reset(new MockInfobarWindow(type, delegate)); + } + + virtual ContainerWindowInterface* CreateContainerWindow( + HWND container, InfobarManager* manager) { + return new MockContainerWindow; + } + + void SetContainerWindow(ContainerWindowInterface* window) { + container_window_.reset(window); + } + + void EmulateOnClose(infobar_api::InfobarType type) { + OnWindowClose(type); + OnContainerWindowDelayedCloseInfobar(type); + } +}; + +class InfobarManagerTests : public testing::Test { + public: + virtual void SetUp() { + infobar_delegate_.reset(new MockInfobarDelegate); + infobar_manager_.reset(new TestingInfobarManager(kGoodWindow)); + + EXPECT_CALL(user32_, IsWindow(kParentWindow)).WillRepeatedly(Return(TRUE)); + EXPECT_CALL(user32_, IsWindow(kGoodWindow)).WillRepeatedly(Return(TRUE)); + EXPECT_CALL(user32_, IsWindow(kInfobarWindow)).WillRepeatedly(Return(TRUE)); + EXPECT_CALL(user32_, IsWindow(NULL)).WillRepeatedly(Return(FALSE)); + EXPECT_CALL(user32_, GetParent(_)).WillRepeatedly(Return(kGoodWindow)); + + // Arbitrary number to return from GetWindowRect. Unique to make it easier + // to trace in the debugger or to add in future tests dependent on return + // values. + RECT window_rect = {131, 213, 831, 1013}; + EXPECT_CALL(user32_, GetWindowRect(_, NotNull())). + WillRepeatedly(DoAll(SetArgumentPointee<1>(window_rect), Return(TRUE))); + } + virtual void TearDown() { + testing::LogDisabler no_dchecks; + infobar_manager_.reset(NULL); + infobar_delegate_.reset(NULL); + + // Everything should have been relinquished. + ASSERT_EQ(0, testing::InstanceCountMixinBase::all_instance_count()); +} + + protected: + static BOOL MockEnumChildWindows(HWND, WNDENUMPROC, LPARAM lparam) { + HWND* window_handle = reinterpret_cast<HWND*>(lparam); + if (window_handle) + *window_handle = kParentWindow; + return TRUE; + } + + StrictMock<testing::MockUser32> user32_; + scoped_ptr<MockInfobarDelegate> infobar_delegate_; + scoped_ptr<TestingInfobarManager> infobar_manager_; +}; + +TEST_F(InfobarManagerTests, GetContainerWindow) { + EXPECT_CALL(user32_, EnumChildWindows(kGoodWindow, _, _)). + WillOnce(Invoke(MockEnumChildWindows)); + + ASSERT_EQ(kParentWindow, infobar_manager_->GetContainerWindow()); + // Next time it should not call EnumChildWindows. + ASSERT_EQ(kParentWindow, infobar_manager_->GetContainerWindow()); +} + +TEST_F(InfobarManagerTests, ShowHide) { + infobar_manager_->InitInfobarWindow(infobar_api::TOP_INFOBAR, + infobar_delegate_.get()); + + // Test Show first. + MockInfobarWindow* infobar_window = + infobar_manager_->GetInfobarWindow(infobar_api::TOP_INFOBAR); + const std::wstring url(kUrl1); + EXPECT_CALL(*infobar_window, Navigate(url)).WillOnce(Return(S_OK)); + EXPECT_CALL(*infobar_window, InternalCreate(kGoodWindow, _)). + WillOnce(WithoutArgs(Invoke(infobar_window, + &MockInfobarWindow::SetInfobarHwnd))); + EXPECT_CALL(*infobar_window, Show(kMaxHeight, false)); + EXPECT_CALL(*infobar_delegate_, GetContainerWindow()). + WillRepeatedly(Return(kParentWindow)); + EXPECT_CALL(user32_, SetWindowPos(_, _, _, _, _, _, _)). + WillRepeatedly(Return(TRUE)); + + EXPECT_HRESULT_SUCCEEDED(infobar_manager_->Show(infobar_api::TOP_INFOBAR, + kMaxHeight, kUrl1, false)); + + // Test Hide for this infobar two times. The second Hide should still be OK + // even though the infobar is already hidden. + EXPECT_CALL(*infobar_window, Reset()).Times(2); + EXPECT_HRESULT_SUCCEEDED(infobar_manager_->Hide(infobar_api::TOP_INFOBAR)); + EXPECT_HRESULT_SUCCEEDED(infobar_manager_->Hide(infobar_api::TOP_INFOBAR)); + + // However Hide to non-existent infobar should result in an error. + EXPECT_HRESULT_FAILED(infobar_manager_->Hide(infobar_api::BOTTOM_INFOBAR)); + EXPECT_HRESULT_FAILED(infobar_manager_->Hide( + static_cast<infobar_api::InfobarType>(55))); + + // HideAll hides only the existing infobar. + EXPECT_CALL(*infobar_window, Reset()); + infobar_manager_->HideAll(); +} + +TEST_F(InfobarManagerTests, OnClose) { + infobar_manager_->InitInfobarWindow(infobar_api::TOP_INFOBAR, + infobar_delegate_.get()); + TestingInfobarManager::MockContainerWindow* container_window = + new TestingInfobarManager::MockContainerWindow; + infobar_manager_->SetContainerWindow(container_window); + EXPECT_CALL(*container_window, PostWindowsMessage(_, _, _)); + MockInfobarWindow* infobar_window = + infobar_manager_->GetInfobarWindow(infobar_api::TOP_INFOBAR); + EXPECT_CALL(*infobar_window, Reset()); + infobar_manager_->EmulateOnClose(infobar_api::TOP_INFOBAR); +} + +} // namespace diff --git a/ceee/ie/plugin/bho/infobar_window.cc b/ceee/ie/plugin/bho/infobar_window.cc index f7c06c1..d484670 100644 --- a/ceee/ie/plugin/bho/infobar_window.cc +++ b/ceee/ie/plugin/bho/infobar_window.cc @@ -41,7 +41,8 @@ InfobarWindow::InfobarWindow(InfobarType type, Delegate* delegate) show_(false), target_height_(1), current_height_(1), - sliding_infobar_(false) { + sliding_infobar_(false), + timer_id_(0) { DCHECK(delegate); } @@ -165,7 +166,7 @@ void InfobarWindow::StartUpdatingLayout(bool show, int max_height, bool slide) { current_height_ = target_height_; if (sliding_infobar_) { - KillTimer(kInfobarSlidingTimerId); + KillTimer(timer_id_); sliding_infobar_ = false; } } else { @@ -174,7 +175,9 @@ void InfobarWindow::StartUpdatingLayout(bool show, int max_height, bool slide) { current_height_ = CalculateNextHeight(); if (!sliding_infobar_) { - SetTimer(kInfobarSlidingTimerId, kInfobarSlidingTimerIntervalMs, NULL); + // Set timer and store its id (it could be different from the passed one). + timer_id_ = SetTimer(kInfobarSlidingTimerId, + kInfobarSlidingTimerIntervalMs, NULL); sliding_infobar_ = true; } } @@ -258,12 +261,12 @@ HRESULT InfobarWindow::GetContentSize(SIZE* size) { } LRESULT InfobarWindow::OnTimer(UINT_PTR nIDEvent) { - DCHECK(nIDEvent == kInfobarSlidingTimerId); + DCHECK(nIDEvent == timer_id_); if (show_ && sliding_infobar_ && current_height_ != target_height_) { current_height_ = CalculateNextHeight(); UpdateLayout(); } else if (sliding_infobar_) { - KillTimer(kInfobarSlidingTimerId); + KillTimer(timer_id_); sliding_infobar_ = false; } diff --git a/ceee/ie/plugin/bho/infobar_window.h b/ceee/ie/plugin/bho/infobar_window.h index 6b373b06..9d8aa5c 100644 --- a/ceee/ie/plugin/bho/infobar_window.h +++ b/ceee/ie/plugin/bho/infobar_window.h @@ -55,13 +55,13 @@ class InfobarWindow : public InfobarBrowserWindow::Delegate, // max_height if the content is too high; no limit if max_height is set to // 0). // slide indicates whether to show sliding effect. - HRESULT Show(int max_height, bool slide); + virtual HRESULT Show(int max_height, bool slide); // Hides the infobar. - HRESULT Hide(); + virtual HRESULT Hide(); // Navigates the HTML view of the infobar. - HRESULT Navigate(const std::wstring& url); + virtual HRESULT Navigate(const std::wstring& url); // Reserves space for the infobar when IE window recalculates its size. void ReserveSpace(RECT* rect); @@ -71,7 +71,11 @@ class InfobarWindow : public InfobarBrowserWindow::Delegate, void UpdatePosition(); // Destroys the browser window. - void Reset(); + virtual void Reset(); + + virtual HWND InternalCreate(HWND parent_window, DWORD style) { + return Create(parent_window, NULL, NULL, style); + } private: BEGIN_MSG_MAP(InfobarWindow) @@ -103,6 +107,9 @@ class InfobarWindow : public InfobarBrowserWindow::Delegate, // Indicates whether the infobar is sliding. bool sliding_infobar_; + // Timer id when sliding the infobar. + UINT_PTR timer_id_; + // The Chrome Frame host handling a Chrome Frame instance for us. CComPtr<IInfobarBrowserWindow> chrome_frame_host_; diff --git a/ceee/ie/plugin/bho/infobar_window_unittest.cc b/ceee/ie/plugin/bho/infobar_window_unittest.cc new file mode 100644 index 0000000..378b09f --- /dev/null +++ b/ceee/ie/plugin/bho/infobar_window_unittest.cc @@ -0,0 +1,181 @@ +// Copyright (c) 2010 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. +// +// Infobar window implementation unit tests. + +// MockWin32 must not be included after atlwin, which is included by some +// headers in here, so we need to put it at the top: +#include "ceee/testing/utils/mock_win32.h" // NOLINT + +#include "ceee/ie/plugin/bho/infobar_window.h" +#include "ceee/testing/utils/instance_count_mixin.h" +#include "ceee/testing/utils/test_utils.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +#include "broker_lib.h" // NOLINT + +namespace { + +using testing::_; +using testing::NotNull; +using testing::Return; +using testing::SetArgumentPointee; +using testing::StrEq; +using testing::StrictMock; + +const HWND kGoodWindow = reinterpret_cast<HWND>(42); +const HWND kParentWindow = reinterpret_cast<HWND>(74); +const wchar_t* kUrl1 = L"/infobar/test.html"; +const int kMaxHeight = 25; +const UINT_PTR timer_id = 19; + +class MockInfobarBrowserWindow : public infobar_api::IInfobarBrowserWindow { + public: + MockInfobarBrowserWindow() : ref_count(0) {} + ~MockInfobarBrowserWindow() { EXPECT_EQ(0, ref_count); } + STDMETHOD_(ULONG, AddRef)() { return ++ref_count; } + STDMETHOD_(ULONG, Release)() { return --ref_count; } + STDMETHOD(QueryInterface)(REFIID, LPVOID*) { return S_OK; } + + MOCK_METHOD1_WITH_CALLTYPE(__stdcall, CreateAndShowWindow, HRESULT(HWND)); + MOCK_METHOD1_WITH_CALLTYPE(__stdcall, SetUrl, HRESULT(BSTR)); + MOCK_METHOD2_WITH_CALLTYPE(__stdcall, SetWindowSize, HRESULT(int, int)); + MOCK_METHOD0_WITH_CALLTYPE(__stdcall, Teardown, HRESULT()); + + ULONG ref_count; +}; + +class MockInfobarWindowDelegate : public infobar_api::InfobarWindow::Delegate { + public: + MOCK_METHOD0(GetContainerWindow, HWND()); + MOCK_METHOD1(OnWindowClose, void(infobar_api::InfobarType)); +}; + +class TestingInfobarWindow : public infobar_api::InfobarWindow { + public: + TestingInfobarWindow(infobar_api::InfobarType type, + InfobarWindow::Delegate* delegate, + MockInfobarBrowserWindow* browser_window) + : infobar_api::InfobarWindow(type, delegate) { + chrome_frame_host_ = browser_window; + } +}; + +class InfobarWindowTests : public testing::Test { + public: + virtual void SetUp() { + infobar_window_delegate_.reset(new StrictMock<MockInfobarWindowDelegate>); + browser_window_.reset(new StrictMock<MockInfobarBrowserWindow>); + infobar_window_.reset(new StrictMock<TestingInfobarWindow>( + infobar_api::TOP_INFOBAR, infobar_window_delegate_.get(), + browser_window_.get())); + infobar_window_->m_hWnd = kGoodWindow; + + EXPECT_CALL(*browser_window_, Teardown()).WillOnce(Return(S_OK)); + EXPECT_CALL(*infobar_window_delegate_, GetContainerWindow()). + WillRepeatedly(Return(kParentWindow)); + + EXPECT_CALL(user32_, IsWindow(kGoodWindow)).WillRepeatedly(Return(TRUE)); + EXPECT_CALL(user32_, IsWindow(kParentWindow)).WillRepeatedly(Return(TRUE)); + EXPECT_CALL(user32_, IsWindow(NULL)).WillRepeatedly(Return(FALSE)); + EXPECT_CALL(user32_, GetParent(_)).WillRepeatedly(Return(kParentWindow)); + + // Arbitrary number to return from GetWindowRect. Unique to make it easier + // to trace in the debugger or to add in future tests dependent on return + // values. + RECT window_rect = {131, 213, 831, 1013}; + EXPECT_CALL(user32_, GetWindowRect(kParentWindow, NotNull())). + WillRepeatedly(DoAll(SetArgumentPointee<1>(window_rect), Return(TRUE))); + EXPECT_CALL(user32_, SetWindowPos(_, _, _, _, _, _, _)). + WillRepeatedly(Return(TRUE)); + } + virtual void TearDown() { + testing::LogDisabler no_dchecks; + // Infobar window must be deleted before delegate as the destructor will + // call the delegate member functions. + infobar_window_.reset(NULL); + infobar_window_delegate_.reset(NULL); + + // Everything should have been relinquished. + ASSERT_EQ(0, testing::InstanceCountMixinBase::all_instance_count()); +} + + protected: + StrictMock<testing::MockUser32> user32_; + scoped_ptr<StrictMock<MockInfobarWindowDelegate>> infobar_window_delegate_; + scoped_ptr<StrictMock<TestingInfobarWindow>> infobar_window_; + scoped_ptr<StrictMock<MockInfobarBrowserWindow>> browser_window_; +}; + +TEST_F(InfobarWindowTests, ShowHide) { + // Show without previous Navigate should fail. + EXPECT_HRESULT_FAILED(infobar_window_->Show(kMaxHeight, false)); + + // Navigate, then Show. + EXPECT_CALL(*browser_window_, SetUrl(StrEq(kUrl1))).Times(1); + EXPECT_HRESULT_SUCCEEDED(infobar_window_->Navigate(std::wstring(kUrl1))); + EXPECT_HRESULT_SUCCEEDED(infobar_window_->Show(kMaxHeight, false)); + EXPECT_EQ(kMaxHeight, infobar_window_->target_height_); + EXPECT_EQ(kMaxHeight, infobar_window_->current_height_); + EXPECT_TRUE(infobar_window_->show_); + + EXPECT_HRESULT_SUCCEEDED(infobar_window_->Hide()); + EXPECT_FALSE(infobar_window_->show_); +} + +TEST_F(InfobarWindowTests, SlidingShow) { + EXPECT_CALL(*browser_window_, SetUrl(StrEq(kUrl1))).Times(1); + EXPECT_HRESULT_SUCCEEDED(infobar_window_->Navigate(std::wstring(kUrl1))); + EXPECT_CALL(user32_, SetTimer(kGoodWindow, _, _, _)). + WillRepeatedly(Return(timer_id)); + EXPECT_HRESULT_SUCCEEDED(infobar_window_->Show(kMaxHeight, true)); + EXPECT_EQ(kMaxHeight, infobar_window_->target_height_); + // With sliding enabled, the hight of the infobar should not be the target + // height immediately - it increases on each timer tick until reaches target. + EXPECT_LE(infobar_window_->current_height_, kMaxHeight); + EXPECT_TRUE(infobar_window_->show_); + EXPECT_TRUE(infobar_window_->sliding_infobar_); + + // Call timer callback function until required. + EXPECT_CALL(user32_, KillTimer(kGoodWindow, timer_id)).WillOnce(Return(TRUE)); + // Restrict the maximum number of times the loop can run so the test does not + // hang if infobar_window_->sliding_infobar_ is not set. Normally it should + // run just a few times (3 times if kMaxHeight is 25 and sliding step is 10). + for (int i = 0; infobar_window_->sliding_infobar_ && i < 100; ++i) { + infobar_window_->OnTimer(timer_id); + } + // Check that the loop is exited because of sliding_infobar_ condition and not + // the counter saturation. + EXPECT_FALSE(infobar_window_->sliding_infobar_); + EXPECT_EQ(kMaxHeight, infobar_window_->current_height_); + EXPECT_TRUE(infobar_window_->show_); +} + +TEST_F(InfobarWindowTests, OnClose) { + EXPECT_CALL(*infobar_window_delegate_, + OnWindowClose(infobar_api::TOP_INFOBAR)).Times(1); + + infobar_window_->OnBrowserWindowClose(); +} + +TEST_F(InfobarWindowTests, ReserveSpace) { + // Arbitrary number to return from GetWindowRect. Unique to make it easier + // to trace in the debugger. + CRect rect1(255, 311, 814, 1015); + CRect rect0 = rect1; + infobar_window_->ReserveSpace(&rect1); + EXPECT_EQ(rect0, rect1); + + EXPECT_CALL(*browser_window_, SetUrl(StrEq(kUrl1))).Times(1); + EXPECT_HRESULT_SUCCEEDED(infobar_window_->Navigate(std::wstring(kUrl1))); + EXPECT_HRESULT_SUCCEEDED(infobar_window_->Show(kMaxHeight, false)); + infobar_window_->ReserveSpace(&rect1); + EXPECT_EQ(rect0.left, rect1.left); + EXPECT_EQ(rect0.right, rect1.right); + EXPECT_EQ(rect0.top + kMaxHeight, rect1.top); + EXPECT_EQ(rect0.bottom, rect1.bottom); +} + +} // namespace |