| // 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. |
| |
| #include "chrome_frame/external_tab.h" |
| #include "base/task.h" |
| #include "base/thread.h" |
| #include "base/tracked.h" |
| |
| // #include "base/waitable_event.h" |
| |
| #include "chrome/common/automation_messages.h" |
| #include "chrome_frame/navigation_constraints.h" |
| #include "chrome_frame/test/chrome_frame_test_utils.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gmock_mutant.h" |
| |
| |
| |
| // DISABLE_RUNNABLE_METHOD_REFCOUNT(ExternalTabProxy); |
| // DISABLE_RUNNABLE_METHOD_REFCOUNT(UIDelegate); |
| DISABLE_RUNNABLE_METHOD_REFCOUNT(ChromeProxyDelegate); |
| |
| using testing::StrictMock; |
| using testing::_; |
| using testing::Invoke; |
| using testing::InvokeWithoutArgs; |
| using testing::CreateFunctor; |
| using testing::Return; |
| using testing::DoAll; |
| using testing::Field; |
| using chrome_frame_test::TimedMsgLoop; |
| |
| struct MockUIDelegate : public UIDelegate { |
| MOCK_METHOD2(OnNavigationStateChanged, void(int flags, |
| const NavigationInfo& nav_info)); |
| MOCK_METHOD1(OnUpdateTargetUrl, void(const std::wstring& new_target_url)); |
| MOCK_METHOD3(OnExtensionInstalled, void(const FilePath& path, void* user_data, |
| AutomationMsg_ExtensionResponseValues response)); |
| MOCK_METHOD1(OnLoad, void(const GURL& url)); |
| MOCK_METHOD3(OnMessageFromChromeFrame, void(const std::string& message, |
| const std::string& origin, const std::string& target)); |
| MOCK_METHOD3(OnHandleContextMenu, void(HANDLE menu_handle, int align_flags, |
| const MiniContextMenuParams& params)); |
| MOCK_METHOD1(OnHandleAccelerator, void(const MSG& accel_message)); |
| MOCK_METHOD1(OnTabbedOut, void(bool reverse)); |
| MOCK_METHOD1(OnGoToHistoryOffset, void(int offset)); |
| MOCK_METHOD3(OnOpenURL, void(const GURL& url_to_open, const GURL& referrer, |
| int open_disposition)); |
| }; |
| |
| struct MockProxy : public ChromeProxy { |
| MOCK_METHOD1(RemoveBrowsingData, void(int remove_mask)); |
| MOCK_METHOD3(InstallExtension, void(ChromeProxyDelegate* delegate, |
| const FilePath& crx_path, SyncMessageContext* ctx)); |
| MOCK_METHOD3(LoadExtension, void(ChromeProxyDelegate* delegate, |
| const FilePath& path, SyncMessageContext* ctx)); |
| MOCK_METHOD2(GetEnabledExtensions, void(ChromeProxyDelegate* delegate, |
| SyncMessageContext* ctx)); |
| MOCK_METHOD1(SetProxyConfig, void(const std::string& json_encoded_settings)); |
| |
| MOCK_METHOD2(CreateTab, void(ChromeProxyDelegate* delegate, |
| const ExternalTabSettings& settings)); |
| MOCK_METHOD3(ConnectTab, void(ChromeProxyDelegate* delegate, HWND hwnd, |
| uint64 cookie)); |
| MOCK_METHOD1(BlockTab, void(uint64 cookie)); |
| |
| MOCK_METHOD4(Tab_PostMessage, void(int tab, const std::string& message, |
| const std::string& origin, const std::string& target)); |
| MOCK_METHOD1(Tab_Reload, void(int tab)); |
| MOCK_METHOD1(Tab_Stop, void(int tab)); |
| MOCK_METHOD1(Tab_SaveAs, void(int tab)); |
| MOCK_METHOD1(Tab_Print, void(int tab)); |
| MOCK_METHOD1(Tab_Cut, void(int tab)); |
| MOCK_METHOD1(Tab_Copy, void(int tab)); |
| MOCK_METHOD1(Tab_Paste, void(int tab)); |
| MOCK_METHOD1(Tab_SelectAll, void(int tab)); |
| MOCK_METHOD5(Tab_Find, void(int tab, const string16& search_string, |
| FindInPageDirection forward, FindInPageCase match_case, bool find_next)); |
| MOCK_METHOD2(Tab_MenuCommand, void(int tab, int selected_command)); |
| |
| MOCK_METHOD2(Tab_Zoom, void(int tab, PageZoom::Function zoom_level)); |
| MOCK_METHOD2(Tab_FontSize, void(int tab, AutomationPageFontSize font_size)); |
| MOCK_METHOD3(Tab_SetInitialFocus, void(int tab, bool reverse, |
| bool restore_focus_to_view)); |
| MOCK_METHOD1(Tab_SetParentWindow, void(int tab)); |
| MOCK_METHOD1(Tab_Resize, void(int tab)); |
| MOCK_METHOD2(Tab_ProcessAccelerator, void(int tab, const MSG& msg)); |
| |
| // Misc. |
| MOCK_METHOD1(Tab_OnHostMoved, void(int tab)); |
| MOCK_METHOD1(Tab_RunUnloadHandlers, void(int tab)); |
| MOCK_METHOD2(Tab_SetEnableExtensionAutomation, void(int tab, |
| const std::vector<std::string>& functions_enabled)); |
| MOCK_METHOD3(Tab_Navigate, void(int tab, const GURL& url, |
| const GURL& referrer)); |
| MOCK_METHOD2(Tab_OverrideEncoding, void(int tab, const char* encoding)); |
| |
| MOCK_METHOD1(Init, void(const ProxyParams& params)); |
| MOCK_METHOD1(AddDelegate, int(ChromeProxyDelegate* delegate)); |
| MOCK_METHOD1(RemoveDelegate, int(ChromeProxyDelegate* delegate)); |
| }; |
| |
| struct MockFactory : public ChromeProxyFactory { |
| MOCK_METHOD0(CreateProxy, ChromeProxy*()); |
| }; |
| |
| |
| // This class just calls methods of ChromeProxyDelegate but in background thread |
| struct AsyncEventCreator { |
| public: |
| explicit AsyncEventCreator(ChromeProxyDelegate* delegate) |
| : delegate_(delegate), ipc_thread_("ipc") { |
| base::Thread::Options options(MessageLoop::TYPE_IO, 0); |
| ipc_thread_.StartWithOptions(options); |
| ipc_loop_ = ipc_thread_.message_loop(); |
| } |
| |
| void Fire_Connected(ChromeProxy* proxy, base::TimeDelta delay) { |
| ipc_loop_->PostDelayedTask(FROM_HERE, NewRunnableMethod(delegate_, |
| &ChromeProxyDelegate::Connected, proxy), delay.InMilliseconds()); |
| } |
| |
| void Fire_PeerLost(ChromeProxy* proxy, |
| ChromeProxyDelegate::DisconnectReason reason, base::TimeDelta delay) { |
| ipc_loop_->PostDelayedTask(FROM_HERE, NewRunnableMethod(delegate_, |
| &ChromeProxyDelegate::PeerLost, proxy, reason), delay.InMilliseconds()); |
| } |
| |
| void Fire_Disconnected(base::TimeDelta delay) { |
| ipc_loop_->PostDelayedTask(FROM_HERE, NewRunnableMethod(delegate_, |
| &ChromeProxyDelegate::Disconnected), delay.InMilliseconds()); |
| } |
| |
| void Fire_CompletedCreateTab(bool success, HWND chrome_wnd, HWND tab_window, |
| int tab_handle, int session_id, |
| base::TimeDelta delay) { |
| ipc_loop_->PostDelayedTask(FROM_HERE, NewRunnableMethod(delegate_, |
| &ChromeProxyDelegate::Completed_CreateTab, success, chrome_wnd, |
| tab_window, tab_handle, session_id), delay.InMilliseconds()); |
| } |
| |
| private: |
| ChromeProxyDelegate* delegate_; |
| base::Thread ipc_thread_; |
| MessageLoop* ipc_loop_; |
| }; |
| |
| // We may want the same test with 'real' proxy and mock 'proxy traits'. |
| TEST(ExternalTabProxy, CancelledCreateTab) { |
| MockUIDelegate ui_delegate; |
| StrictMock<MockFactory> factory; |
| scoped_ptr<ExternalTabProxy> tab(new ExternalTabProxy()); |
| AsyncEventCreator async_events(tab.get()); |
| StrictMock<MockProxy>* proxy = new StrictMock<MockProxy>(); |
| TimedMsgLoop loop; |
| tab->set_proxy_factory(&factory); |
| |
| EXPECT_CALL(factory, CreateProxy()).WillOnce(Return(proxy)); |
| EXPECT_CALL(*proxy, Init(_)); |
| EXPECT_CALL(*proxy, AddDelegate(tab.get())).WillOnce(DoAll(InvokeWithoutArgs( |
| CreateFunctor(&async_events, &AsyncEventCreator::Fire_Connected, |
| proxy, base::TimeDelta::FromMilliseconds(30))), |
| Return(1))); |
| |
| EXPECT_CALL(*proxy, CreateTab(tab.get(), _)) |
| .WillOnce(QUIT_LOOP(loop)); |
| |
| EXPECT_CALL(*proxy, RemoveDelegate(_)).WillOnce(DoAll( |
| InvokeWithoutArgs(CreateFunctor(&async_events, |
| &AsyncEventCreator::Fire_CompletedCreateTab, false, HWND(0), HWND(0), |
| 0, 0, base::TimeDelta::FromMilliseconds(0))), |
| InvokeWithoutArgs(CreateFunctor(&async_events, |
| &AsyncEventCreator::Fire_Disconnected, |
| base::TimeDelta::FromMilliseconds(0))), |
| Return(0))); |
| |
| CreateTabParams tab_params; |
| tab_params.is_incognito = true; |
| tab_params.is_widget_mode = false; |
| tab_params.url = GURL("http://Xanadu.org"); |
| |
| tab->CreateTab(tab_params, &ui_delegate); |
| loop.RunFor(5); |
| EXPECT_FALSE(loop.WasTimedOut()); |
| tab.reset(); |
| } |