diff options
Diffstat (limited to 'chrome_frame')
-rw-r--r-- | chrome_frame/chrome_frame.gyp | 8 | ||||
-rw-r--r-- | chrome_frame/test/chrome_frame_test_utils.cc | 9 | ||||
-rw-r--r-- | chrome_frame/test/chrome_frame_test_utils.h | 65 | ||||
-rw-r--r-- | chrome_frame/test/net/dialog_watchdog.cc | 146 | ||||
-rw-r--r-- | chrome_frame/test/net/dialog_watchdog.h | 64 | ||||
-rw-r--r-- | chrome_frame/test/net/fake_external_tab.cc | 104 | ||||
-rw-r--r-- | chrome_frame/test/simulate_input.cc | 20 | ||||
-rw-r--r-- | chrome_frame/test/simulate_input.h | 3 | ||||
-rw-r--r-- | chrome_frame/test/test_mock_with_web_server.cc | 288 | ||||
-rw-r--r-- | chrome_frame/test/test_mock_with_web_server.h | 8 | ||||
-rw-r--r-- | chrome_frame/test/window_watchdog.cc | 89 | ||||
-rw-r--r-- | chrome_frame/test/window_watchdog.h | 60 |
12 files changed, 580 insertions, 284 deletions
diff --git a/chrome_frame/chrome_frame.gyp b/chrome_frame/chrome_frame.gyp index 6516581..631788a 100644 --- a/chrome_frame/chrome_frame.gyp +++ b/chrome_frame/chrome_frame.gyp @@ -215,6 +215,8 @@ 'test/test_with_web_server.cc', 'test/test_with_web_server.h', 'test/url_request_test.cc', + 'test/window_watchdog.cc', + 'test/window_watchdog.h', 'chrome_frame_automation.cc', 'chrome_frame_histograms.h', 'chrome_frame_histograms.cc', @@ -347,8 +349,8 @@ 'test/simulate_input.h', 'test/test_server.cc', 'test/test_server.h', - 'test/net/dialog_watchdog.cc', - 'test/net/dialog_watchdog.h', + 'test/window_watchdog.cc', + 'test/window_watchdog.h', 'test/net/fake_external_tab.cc', 'test/net/fake_external_tab.h', 'test/net/process_singleton_subclass.cc', @@ -412,6 +414,8 @@ 'test_utils.h', 'test/simulate_input.cc', 'test/simulate_input.h', + 'test/window_watchdog.cc', + 'test/window_watchdog.h', 'chrome_tab.h', 'chrome_tab.idl', '../base/test/test_file_util_win.cc', diff --git a/chrome_frame/test/chrome_frame_test_utils.cc b/chrome_frame/test/chrome_frame_test_utils.cc index 55f934c..4753611 100644 --- a/chrome_frame/test/chrome_frame_test_utils.cc +++ b/chrome_frame/test/chrome_frame_test_utils.cc @@ -750,6 +750,15 @@ void WebBrowserEventSink::Exec(const GUID* cmd_group_guid, DWORD command_id, command_id, cmd_exec_opt, in_args, out_args)); } +void WebBrowserEventSink::WatchChromeWindow(const wchar_t* window_class) { + DCHECK(window_class); + window_watcher_.AddObserver(this, WideToUTF8(window_class)); +} + +void WebBrowserEventSink::StopWatching() { + window_watcher_.RemoveObserver(this); +} + void WebBrowserEventSink::NavigateBackward() { SetFocusToChrome(); simulate_input::SendMnemonic(VK_BACK, false, false, false, false, false); diff --git a/chrome_frame/test/chrome_frame_test_utils.h b/chrome_frame/test/chrome_frame_test_utils.h index 0109b39..3c000c9 100644 --- a/chrome_frame/test/chrome_frame_test_utils.h +++ b/chrome_frame/test/chrome_frame_test_utils.h @@ -23,6 +23,7 @@ #include "chrome_frame/test_utils.h" #include "chrome_frame/test/simulate_input.h" +#include "chrome_frame/test/window_watchdog.h" // Include without path to make GYP build see it. #include "chrome_tab.h" // NOLINT @@ -129,7 +130,8 @@ HRESULT LaunchIEAsComServer(IWebBrowser2** web_browser); class WebBrowserEventSink : public CComObjectRootEx<CComMultiThreadModel>, public IDispEventSimpleImpl<0, WebBrowserEventSink, - &DIID_DWebBrowserEvents2> { + &DIID_DWebBrowserEvents2>, + public WindowObserver { public: typedef IDispEventSimpleImpl<0, WebBrowserEventSink, &DIID_DWebBrowserEvents2> DispEventsImpl; @@ -148,6 +150,30 @@ class WebBrowserEventSink Uninitialize(); } +BEGIN_COM_MAP(WebBrowserEventSink) +END_COM_MAP() + +BEGIN_SINK_MAP(WebBrowserEventSink) + SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_BEFORENAVIGATE2, + OnBeforeNavigate2Internal, &kBeforeNavigate2Info) + SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_DOWNLOADBEGIN, + OnDownloadBegin, &kVoidMethodInfo) + SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_NAVIGATECOMPLETE2, + OnNavigateComplete2Internal, &kNavigateComplete2Info) + SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_NAVIGATEERROR, + OnNavigateError, &kNavigateErrorInfo) + SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_NEWWINDOW2, + OnNewWindow2, &kNewWindow2Info) + SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_NEWWINDOW3, + OnNewWindow3Internal, &kNewWindow3Info) + SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_DOCUMENTCOMPLETE, + OnDocumentCompleteInternal, &kDocumentCompleteInfo) + SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_FILEDOWNLOAD, + OnFileDownloadInternal, &kFileDownloadInfo) + SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_ONQUIT, + OnQuitInternal, &kVoidMethodInfo) +END_SINK_MAP() + void Attach(IDispatch* browser_disp); void Uninitialize(); @@ -172,6 +198,10 @@ class WebBrowserEventSink void Exec(const GUID* cmd_group_guid, DWORD command_id, DWORD cmd_exec_opt, VARIANT* in_args, VARIANT* out_args); + // Watch for new window created + void WatchChromeWindow(const wchar_t* window_class); + void StopWatching(); + // Navigates to the next item in history by sending the Shift+Back key // combination void NavigateForward(); @@ -179,30 +209,7 @@ class WebBrowserEventSink // Navigates to the next item in history by sending the Backstroke key. void NavigateBackward(); -BEGIN_COM_MAP(WebBrowserEventSink) -END_COM_MAP() - -BEGIN_SINK_MAP(WebBrowserEventSink) - SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_BEFORENAVIGATE2, - OnBeforeNavigate2Internal, &kBeforeNavigate2Info) - SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_DOWNLOADBEGIN, - OnDownloadBegin, &kVoidMethodInfo) - SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_NAVIGATECOMPLETE2, - OnNavigateComplete2Internal, &kNavigateComplete2Info) - SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_NAVIGATEERROR, - OnNavigateError, &kNavigateErrorInfo) - SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_NEWWINDOW2, - OnNewWindow2, &kNewWindow2Info) - SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_NEWWINDOW3, - OnNewWindow3Internal, &kNewWindow3Info) - SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_DOCUMENTCOMPLETE, - OnDocumentCompleteInternal, &kDocumentCompleteInfo) - SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_FILEDOWNLOAD, - OnFileDownloadInternal, &kFileDownloadInfo) - SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_ONQUIT, - OnQuitInternal, &kVoidMethodInfo) -END_SINK_MAP() - + // Overridable methods for the mock STDMETHOD_(void, OnNavigateError)(IDispatch* dispatch, VARIANT* url, VARIANT* frame_name, VARIANT* status_code, VARIANT* cancel) { @@ -252,13 +259,15 @@ END_SINK_MAP() virtual void OnLoadError(const wchar_t* url) {} virtual void OnMessage(const wchar_t* message, const wchar_t* origin, const wchar_t* source) {} + virtual void OnNewBrowserWindow(IDispatch* new_window, const wchar_t* url) {} + + // Window watchdog override + virtual void OnWindowDetected(HWND hwnd, const std::string& caption) {}; IWebBrowser2* web_browser2() { return web_browser2_.get(); } - virtual void OnNewBrowserWindow(IDispatch* new_window, const wchar_t* url) {} - HRESULT SetWebBrowser(IWebBrowser2* web_browser2); void ExpectRendererWindowHasfocus(); @@ -311,6 +320,8 @@ END_SINK_MAP() static _ATL_FUNC_INFO kVoidMethodInfo; static _ATL_FUNC_INFO kDocumentCompleteInfo; static _ATL_FUNC_INFO kFileDownloadInfo; + + WindowWatchdog window_watcher_; }; } // namespace chrome_frame_test diff --git a/chrome_frame/test/net/dialog_watchdog.cc b/chrome_frame/test/net/dialog_watchdog.cc deleted file mode 100644 index 8b2323a..0000000 --- a/chrome_frame/test/net/dialog_watchdog.cc +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright (c) 2009 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 <oleacc.h> - -#include "chrome_frame/test/net/dialog_watchdog.h" - -#include "base/logging.h" -#include "base/scoped_comptr_win.h" -#include "base/string_util.h" - -#include "chrome_frame/test/simulate_input.h" -#include "chrome_frame/function_stub.h" - -namespace { -// Uses the IAccessible interface for the window to set the focus. -// This can be useful when you don't have control over the thread that -// owns the window. -// NOTE: this depends on oleacc.lib which the net tests already depend on -// but other unit tests don't depend on oleacc so we can't just add the method -// directly into chrome_frame_test_utils.cc (without adding a -// #pragma comment(lib, "oleacc.lib")). -bool SetFocusToAccessibleWindow(HWND hwnd) { - bool ret = false; - ScopedComPtr<IAccessible> acc; - AccessibleObjectFromWindow(hwnd, OBJID_WINDOW, IID_IAccessible, - reinterpret_cast<void**>(acc.Receive())); - if (acc) { - VARIANT self = { VT_I4 }; - self.lVal = CHILDID_SELF; - ret = SUCCEEDED(acc->accSelect(SELFLAG_TAKEFOCUS, self)); - } - return ret; -} - -} // namespace - -SupplyProxyCredentials::SupplyProxyCredentials(const char* username, - const char* password) - : username_(username), password_(password) { -} - -bool SupplyProxyCredentials::OnDialogDetected(HWND hwnd, - const std::string& caption) { - // IE's dialog caption (en-US). - if (caption.compare("Windows Security") != 0) - return false; - - DialogProps props = {0}; - ::EnumChildWindows(hwnd, EnumChildren, reinterpret_cast<LPARAM>(&props)); - DCHECK(::IsWindow(props.username_)); - DCHECK(::IsWindow(props.password_)); - - // We can't use SetWindowText to set the username/password, so simulate - // keyboard input instead. - simulate_input::ForceSetForegroundWindow(hwnd); - CHECK(SetFocusToAccessibleWindow(props.username_)); - simulate_input::SendString(username_.c_str()); - Sleep(100); - - simulate_input::SendChar(static_cast<char>(VK_TAB), false, false); - Sleep(100); - simulate_input::SendString(password_.c_str()); - - Sleep(100); - simulate_input::SendChar(static_cast<char>(VK_RETURN), false, false); - - return true; -} - -// static -BOOL SupplyProxyCredentials::EnumChildren(HWND hwnd, LPARAM param) { - if (!::IsWindowVisible(hwnd)) - return TRUE; // Ignore but continue to enumerate. - - DialogProps* props = reinterpret_cast<DialogProps*>(param); - - char class_name[MAX_PATH] = {0}; - ::GetClassNameA(hwnd, class_name, arraysize(class_name)); - if (lstrcmpiA(class_name, "Edit") == 0) { - if (props->username_ == NULL || props->username_ == hwnd) { - props->username_ = hwnd; - } else if (props->password_ == NULL) { - props->password_ = hwnd; - } - } else { - EnumChildWindows(hwnd, EnumChildren, param); - } - - return TRUE; -} - -DialogWatchdog::DialogWatchdog() : hook_(NULL), hook_stub_(NULL) { - Initialize(); -} - -DialogWatchdog::~DialogWatchdog() { - Uninitialize(); -} - -bool DialogWatchdog::Initialize() { - DCHECK(hook_ == NULL); - DCHECK(hook_stub_ == NULL); - hook_stub_ = FunctionStub::Create(reinterpret_cast<uintptr_t>(this), - WinEventHook); - hook_ = SetWinEventHook(EVENT_OBJECT_SHOW, EVENT_OBJECT_SHOW, NULL, - reinterpret_cast<WINEVENTPROC>(hook_stub_->code()), 0, - 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS); - - return hook_ != NULL; -} - -void DialogWatchdog::Uninitialize() { - if (hook_) { - ::UnhookWinEvent(hook_); - hook_ = NULL; - FunctionStub::Destroy(hook_stub_); - hook_stub_ = NULL; - } -} - -// static -void DialogWatchdog::WinEventHook(DialogWatchdog* me, HWINEVENTHOOK hook, - DWORD event, HWND hwnd, LONG object_id, - LONG child_id, DWORD event_thread_id, - DWORD event_time) { - // Check for a dialog class ("#32770") and notify observers if we find one. - char class_name[MAX_PATH] = {0}; - ::GetClassNameA(hwnd, class_name, arraysize(class_name)); - if (lstrcmpA(class_name, "#32770") == 0) { - int len = ::GetWindowTextLength(hwnd); - std::string text; - ::GetWindowTextA(hwnd, WriteInto(&text, len + 1), len + 1); - me->OnDialogFound(hwnd, text); - } -} - -void DialogWatchdog::OnDialogFound(HWND hwnd, const std::string& caption) { - std::vector<DialogWatchdogObserver*>::iterator it = observers_.begin(); - while (it != observers_.end()) { - if ((*it)->OnDialogDetected(hwnd, caption)) - break; - it++; - } -} diff --git a/chrome_frame/test/net/dialog_watchdog.h b/chrome_frame/test/net/dialog_watchdog.h deleted file mode 100644 index dfb8989..0000000 --- a/chrome_frame/test/net/dialog_watchdog.h +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) 2009 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. - -#ifndef CHROME_FRAME_TEST_NET_DIALOG_WATCHDOG_H_ -#define CHROME_FRAME_TEST_NET_DIALOG_WATCHDOG_H_ - -#include <windows.h> - -#include <string> -#include <vector> - -struct FunctionStub; - -class DialogWatchdogObserver { // NOLINT - public: - // returns true if this observer handled the dialog. - virtual bool OnDialogDetected(HWND hwnd, const std::string& caption) = 0; -}; - -class SupplyProxyCredentials : public DialogWatchdogObserver { - public: - SupplyProxyCredentials(const char* username, const char* password); - - protected: - struct DialogProps { - HWND username_; - HWND password_; - }; - - virtual bool OnDialogDetected(HWND hwnd, const std::string& caption); - static BOOL CALLBACK EnumChildren(HWND hwnd, LPARAM param); - - protected: - std::string username_; - std::string password_; -}; - -class DialogWatchdog { - public: - DialogWatchdog(); - ~DialogWatchdog(); - - inline void AddObserver(DialogWatchdogObserver* observer) { - observers_.push_back(observer); - } - - bool Initialize(); - void Uninitialize(); - - protected: - static void CALLBACK WinEventHook(DialogWatchdog* me, HWINEVENTHOOK hook, - DWORD event, HWND hwnd, LONG object_id, LONG child_id, - DWORD event_thread_id, DWORD event_time); - - void OnDialogFound(HWND hwnd, const std::string& caption); - - protected: - HWINEVENTHOOK hook_; - std::vector<DialogWatchdogObserver*> observers_; - FunctionStub* hook_stub_; -}; - -#endif // CHROME_FRAME_TEST_NET_DIALOG_WATCHDOG_H_ diff --git a/chrome_frame/test/net/fake_external_tab.cc b/chrome_frame/test/net/fake_external_tab.cc index cbb1607..ba8a974 100644 --- a/chrome_frame/test/net/fake_external_tab.cc +++ b/chrome_frame/test/net/fake_external_tab.cc @@ -33,7 +33,8 @@ #include "chrome/common/pref_names.h" #include "chrome_frame/utils.h" #include "chrome_frame/test/chrome_frame_test_utils.h" -#include "chrome_frame/test/net/dialog_watchdog.h" +#include "chrome_frame/test/simulate_input.h" +#include "chrome_frame/test/window_watchdog.h" #include "chrome_frame/test/net/test_automation_resource_message_filter.h" namespace { @@ -68,7 +69,101 @@ bool PromptAfterSetup() { return CommandLine::ForCurrentProcess()->HasSwitch(kPromptAfterSetup); } -} // end namespace +// Uses the IAccessible interface for the window to set the focus. +// This can be useful when you don't have control over the thread that +// owns the window. +// NOTE: this depends on oleacc.lib which the net tests already depend on +// but other unit tests don't depend on oleacc so we can't just add the method +// directly into chrome_frame_test_utils.cc (without adding a +// #pragma comment(lib, "oleacc.lib")). +bool SetFocusToAccessibleWindow(HWND hwnd) { + bool ret = false; + ScopedComPtr<IAccessible> acc; + AccessibleObjectFromWindow(hwnd, OBJID_WINDOW, IID_IAccessible, + reinterpret_cast<void**>(acc.Receive())); + if (acc) { + VARIANT self = { VT_I4 }; + self.lVal = CHILDID_SELF; + ret = SUCCEEDED(acc->accSelect(SELFLAG_TAKEFOCUS, self)); + } + return ret; +} + +} // namespace + + +class SupplyProxyCredentials : public WindowObserver { + public: + SupplyProxyCredentials(const char* username, const char* password); + + protected: + struct DialogProps { + HWND username_; + HWND password_; + }; + + virtual void OnWindowDetected(HWND hwnd, const std::string& caption); + static BOOL CALLBACK EnumChildren(HWND hwnd, LPARAM param); + + protected: + std::string username_; + std::string password_; +}; + + +SupplyProxyCredentials::SupplyProxyCredentials(const char* username, + const char* password) + : username_(username), password_(password) { +} + +void SupplyProxyCredentials::OnWindowDetected(HWND hwnd, + const std::string& caption) { + // IE's dialog caption (en-US). + if (caption.compare("Windows Security") != 0) + return; + + DialogProps props = {0}; + ::EnumChildWindows(hwnd, EnumChildren, reinterpret_cast<LPARAM>(&props)); + DCHECK(::IsWindow(props.username_)); + DCHECK(::IsWindow(props.password_)); + + // We can't use SetWindowText to set the username/password, so simulate + // keyboard input instead. + simulate_input::ForceSetForegroundWindow(hwnd); + CHECK(SetFocusToAccessibleWindow(props.username_)); + simulate_input::SendString(username_.c_str()); + Sleep(100); + + simulate_input::SendChar(static_cast<char>(VK_TAB), false, false); + Sleep(100); + simulate_input::SendString(password_.c_str()); + + Sleep(100); + simulate_input::SendChar(static_cast<char>(VK_RETURN), false, false); +} + +// static +BOOL SupplyProxyCredentials::EnumChildren(HWND hwnd, LPARAM param) { + if (!::IsWindowVisible(hwnd)) + return TRUE; // Ignore but continue to enumerate. + + DialogProps* props = reinterpret_cast<DialogProps*>(param); + + char class_name[MAX_PATH] = {0}; + ::GetClassNameA(hwnd, class_name, arraysize(class_name)); + if (lstrcmpiA(class_name, "Edit") == 0) { + if (props->username_ == NULL || props->username_ == hwnd) { + props->username_ = hwnd; + } else if (props->password_ == NULL) { + props->password_ = hwnd; + } + } else { + EnumChildWindows(hwnd, EnumChildren, param); + } + + return TRUE; +} + FakeExternalTab::FakeExternalTab() { PathService::Get(chrome::DIR_USER_DATA, &overridden_user_dir_); @@ -369,10 +464,11 @@ void FilterDisabledTests() { } int main(int argc, char** argv) { - DialogWatchdog watchdog; + WindowWatchdog watchdog; // See url_request_unittest.cc for these credentials. SupplyProxyCredentials credentials("user", "secret"); - watchdog.AddObserver(&credentials); + // Check for a dialog class ("#32770") + watchdog.AddObserver(&credentials, "#32770"); testing::InitGoogleTest(&argc, argv); FilterDisabledTests(); PluginService::EnableChromePlugins(false); diff --git a/chrome_frame/test/simulate_input.cc b/chrome_frame/test/simulate_input.cc index 082b58b..3b8174c 100644 --- a/chrome_frame/test/simulate_input.cc +++ b/chrome_frame/test/simulate_input.cc @@ -111,12 +111,24 @@ bool EnsureProcessInForeground(base::ProcessId process_id) { return ret; } +void SendScanCode(short scan_code, bool shift, bool control, bool alt) { + DCHECK(-1 != scan_code); + + // High order byte in |scan_code| is SHIFT/CTRL/ALT key state. + shift |= !!(HIBYTE(scan_code) & 0x1); + control |= !!(HIBYTE(scan_code) & 0x2); + alt |= !!(HIBYTE(scan_code) & 0x4); + + // Low order byte in |scan_code| is the actual scan code. + SendMnemonic(LOBYTE(scan_code), shift, control, alt, false, true); +} + void SendChar(char c, bool control, bool alt) { - SendMnemonic(toupper(c), !!isupper(c), control, alt, false, false); + SendScanCode(VkKeyScanA(c), false, control, alt); } void SendChar(wchar_t c, bool control, bool alt) { - SendMnemonic(towupper(c), !!iswupper(c), control, alt, false, true); + SendScanCode(VkKeyScanW(c), false, control, alt); } // Sends a keystroke to the currently active application with optional @@ -164,7 +176,7 @@ void SendMnemonic(WORD mnemonic_char, bool shift_pressed, bool control_pressed, SendInput(1, &keys[ i ], sizeof(keys[0])); keys[i].ki.dwFlags |= KEYEVENTF_KEYUP; if (should_sleep) { - Sleep(100); + Sleep(10); } } @@ -172,7 +184,7 @@ void SendMnemonic(WORD mnemonic_char, bool shift_pressed, bool control_pressed, for (int i = key_count; i; i--) { SendInput(1, &keys[ i - 1 ], sizeof(keys[0])); if (should_sleep) { - Sleep(100); + Sleep(10); } } } diff --git a/chrome_frame/test/simulate_input.h b/chrome_frame/test/simulate_input.h index 972269c..e739e8f 100644 --- a/chrome_frame/test/simulate_input.h +++ b/chrome_frame/test/simulate_input.h @@ -35,6 +35,7 @@ enum MouseButton { LEFT, RIGHT, MIDDLE, X }; void SendMouseClick(HWND window, int x, int y, MouseButton button); // Translates a single char to a virtual key and calls SendVirtualKey. +void SendScanCode(short scan_code, bool shift, bool control, bool alt); void SendChar(char c, bool control, bool alt); void SendChar(wchar_t c, bool control, bool alt); @@ -49,7 +50,7 @@ void SendString(const char_type* s) { while (*s) { char_type ch = *s; SendChar(ch, false, false); - Sleep(100); + Sleep(10); s++; } } diff --git a/chrome_frame/test/test_mock_with_web_server.cc b/chrome_frame/test/test_mock_with_web_server.cc index b6b28fc..af14875 100644 --- a/chrome_frame/test/test_mock_with_web_server.cc +++ b/chrome_frame/test/test_mock_with_web_server.cc @@ -22,6 +22,7 @@ const int kChromeFrameLongNavigationTimeoutInSeconds = 10; const wchar_t kChromeFrameFileUrl[] = L"gcf:file:///C:/"; const wchar_t enter_key[] = { VK_RETURN, 0 }; +const wchar_t escape_key[] = { VK_ESCAPE, 0 }; const wchar_t tab_enter_keys[] = { VK_TAB, VK_RETURN, 0 }; // A convenience class to close all open IE windows at the end @@ -239,7 +240,7 @@ TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_FocusTest) { mock.ExpectNavigationAndSwitch(kAboutVersionUrl); - EXPECT_CALL(mock, OnLoad(testing::StrEq(kAboutVersion))) + EXPECT_CALL(mock, OnLoad(testing::StrCaseEq(kAboutVersion))) .WillOnce(testing::DoAll( testing::InvokeWithoutArgs(CreateFunctor(&mock, &MockWebBrowserEventSink::ExpectRendererWindowHasfocus)), @@ -274,7 +275,7 @@ TEST_F(ChromeFrameTestWithWebServer, FLAKY_FullTabModeIE_WindowOpenInChrome) { mock.ExpectNavigationAndSwitch(kFullTabWindowOpenTestUrl); const wchar_t* input = L"A"; - EXPECT_CALL(mock, OnLoad(testing::StrEq(kFullTabWindowOpenTestUrl))) + EXPECT_CALL(mock, OnLoad(testing::StrCaseEq(kFullTabWindowOpenTestUrl))) .WillOnce(testing::InvokeWithoutArgs(CreateFunctor(&loop, &chrome_frame_test::TimedMsgLoop::PostDelayedTask, FROM_HERE, NewRunnableMethod( @@ -285,7 +286,7 @@ TEST_F(ChromeFrameTestWithWebServer, FLAKY_FullTabModeIE_WindowOpenInChrome) { mock.ExpectNewWindow(&new_window_mock); EXPECT_CALL(new_window_mock, - OnLoad(testing::StrEq(kFullTabWindowOpenPopupUrl))) + OnLoad(testing::StrCaseEq(kFullTabWindowOpenPopupUrl))) .WillOnce(testing::IgnoreResult(testing::InvokeWithoutArgs( CreateFunctor(&new_window_mock, &MockWebBrowserEventSink::CloseWebBrowser)))); @@ -327,7 +328,7 @@ TEST_F(ChromeFrameTestWithWebServer, FLAKY_FullTabModeIE_AboutChromeFrame) { mock.ExpectNavigationAndSwitch(kSubFrameUrl1); - EXPECT_CALL(mock, OnLoad(testing::StrEq(kSubFrameUrl1))) + EXPECT_CALL(mock, OnLoad(testing::StrCaseEq(kSubFrameUrl1))) .WillOnce(testing::DoAll( testing::InvokeWithoutArgs(CreateFunctor(&mock, &MockWebBrowserEventSink::SendMouseClick, 10, 10, @@ -347,7 +348,7 @@ TEST_F(ChromeFrameTestWithWebServer, FLAKY_FullTabModeIE_AboutChromeFrame) { ComStackObjectWithUninitialize<MockWebBrowserEventSink> new_window_mock; mock.ExpectNewWindow(&new_window_mock); - EXPECT_CALL(new_window_mock, OnLoad(testing::StrEq(kAboutVersion))) + EXPECT_CALL(new_window_mock, OnLoad(testing::StrCaseEq(kAboutVersion))) .WillOnce(testing::IgnoreResult(testing::InvokeWithoutArgs( CreateFunctor(&new_window_mock, &MockWebBrowserEventSink::CloseWebBrowser)))); @@ -396,7 +397,7 @@ TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_BackForward) { mock.ExpectNavigationAndSwitchSequence(kSubFrameUrl1); // Navigate to url 2 after the previous navigation is complete. - EXPECT_CALL(mock, OnLoad(testing::StrEq(kSubFrameUrl1))) + EXPECT_CALL(mock, OnLoad(testing::StrCaseEq(kSubFrameUrl1))) .WillOnce(testing::IgnoreResult(testing::InvokeWithoutArgs( CreateFunctor( &mock, &chrome_frame_test::WebBrowserEventSink::Navigate, @@ -404,7 +405,7 @@ TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_BackForward) { mock.ExpectNavigationAndSwitchSequence(kSubFrameUrl2); // Navigate to url 3 after the previous navigation is complete - EXPECT_CALL(mock, OnLoad(testing::StrEq(kSubFrameUrl2))) + EXPECT_CALL(mock, OnLoad(testing::StrCaseEq(kSubFrameUrl2))) .WillOnce(testing::IgnoreResult(testing::InvokeWithoutArgs( CreateFunctor( &mock, &chrome_frame_test::WebBrowserEventSink::Navigate, @@ -413,7 +414,7 @@ TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_BackForward) { // We have reached url 3 and have two back entries for url 1 & 2 // Go back to url 2 now mock.ExpectNavigationAndSwitchSequence(kSubFrameUrl3); - EXPECT_CALL(mock, OnLoad(testing::StrEq(kSubFrameUrl3))) + EXPECT_CALL(mock, OnLoad(testing::StrCaseEq(kSubFrameUrl3))) .WillOnce(testing::IgnoreResult(testing::InvokeWithoutArgs( CreateFunctor(ReceivePointer(mock.web_browser2_), &IWebBrowser::GoBack)))); @@ -421,7 +422,7 @@ TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_BackForward) { // We have reached url 2 and have 1 back & 1 forward entries for url 1 & 3 // Go back to url 1 now mock.ExpectNavigation(kSubFrameUrl2); - EXPECT_CALL(mock, OnLoad(testing::StrEq(kSubFrameUrl2))) + EXPECT_CALL(mock, OnLoad(testing::StrCaseEq(kSubFrameUrl2))) .WillOnce(testing::IgnoreResult(testing::InvokeWithoutArgs( CreateFunctor(ReceivePointer(mock.web_browser2_), &IWebBrowser::GoBack)))); @@ -429,7 +430,7 @@ TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_BackForward) { // We have reached url 1 and have 0 back & 2 forward entries for url 2 & 3 // Go back to url 1 now mock.ExpectNavigation(kSubFrameUrl1); - EXPECT_CALL(mock, OnLoad(testing::StrEq(kSubFrameUrl1))) + EXPECT_CALL(mock, OnLoad(testing::StrCaseEq(kSubFrameUrl1))) .WillOnce(testing::IgnoreResult(testing::InvokeWithoutArgs( CreateFunctor(&mock, &MockWebBrowserEventSink::CloseWebBrowser)))); @@ -480,7 +481,7 @@ TEST_F(ChromeFrameTestWithWebServer, FLAKY_FullTabModeIE_BackForwardAnchor) { // It's better to send input as PostDelayedTask since the Activex // message loop on the other side might be blocked when we get // called in Onload. - EXPECT_CALL(mock, OnLoad(testing::StrEq(kAnchorUrl))) + EXPECT_CALL(mock, OnLoad(testing::StrCaseEq(kAnchorUrl))) .WillOnce(testing::DoAll( testing::InvokeWithoutArgs(CreateFunctor(&mock, &chrome_frame_test::WebBrowserEventSink::SetFocusToChrome)), @@ -495,7 +496,7 @@ TEST_F(ChromeFrameTestWithWebServer, FLAKY_FullTabModeIE_BackForwardAnchor) { // Back/Forward state at this point: // Back: 1 (kAnchorUrl) // Forward: 0 - EXPECT_CALL(mock, OnLoad(testing::StrEq(kAnchor1Url))) + EXPECT_CALL(mock, OnLoad(testing::StrCaseEq(kAnchor1Url))) .WillOnce(testing::InvokeWithoutArgs( CreateFunctor( &loop, &chrome_frame_test::TimedMsgLoop::PostDelayedTask, @@ -509,7 +510,7 @@ TEST_F(ChromeFrameTestWithWebServer, FLAKY_FullTabModeIE_BackForwardAnchor) { // Back/Forward state at this point: // Back: 2 (kAnchorUrl, kAnchor1Url) // Forward: 0 - EXPECT_CALL(mock, OnLoad(testing::StrEq(kAnchor2Url))) + EXPECT_CALL(mock, OnLoad(testing::StrCaseEq(kAnchor2Url))) .WillOnce(testing::InvokeWithoutArgs( CreateFunctor( &loop, &chrome_frame_test::TimedMsgLoop::PostDelayedTask, @@ -524,7 +525,7 @@ TEST_F(ChromeFrameTestWithWebServer, FLAKY_FullTabModeIE_BackForwardAnchor) { // Back/Forward state at this point: // Back: 3 (kAnchorUrl, kAnchor1Url, kAnchor2Url) // Forward: 0 - EXPECT_CALL(mock, OnLoad(testing::StrEq(kAnchor3Url))) + EXPECT_CALL(mock, OnLoad(testing::StrCaseEq(kAnchor3Url))) .WillOnce(testing::IgnoreResult(testing::InvokeWithoutArgs( CreateFunctor(ReceivePointer(mock.web_browser2_), &IWebBrowser::GoBack)))); @@ -535,7 +536,7 @@ TEST_F(ChromeFrameTestWithWebServer, FLAKY_FullTabModeIE_BackForwardAnchor) { // Back/Forward state at this point: // Back: 3 (kAnchorUrl, kAnchor1Url, kAnchor2Url) // Forward: 1 (kAnchor3Url) - EXPECT_CALL(mock, OnLoad(testing::StrEq(kAnchor2Url))) + EXPECT_CALL(mock, OnLoad(testing::StrCaseEq(kAnchor2Url))) .WillOnce(testing::IgnoreResult(testing::InvokeWithoutArgs( CreateFunctor(ReceivePointer(mock.web_browser2_), &IWebBrowser::GoBack)))); @@ -546,7 +547,7 @@ TEST_F(ChromeFrameTestWithWebServer, FLAKY_FullTabModeIE_BackForwardAnchor) { // Back/Forward state at this point: // Back: 2 (kAnchorUrl, kAnchor1Url) // Forward: 2 (kAnchor2Url, kAnchor3Url) - EXPECT_CALL(mock, OnLoad(testing::StrEq(kAnchor1Url))) + EXPECT_CALL(mock, OnLoad(testing::StrCaseEq(kAnchor1Url))) .WillOnce(testing::IgnoreResult(testing::InvokeWithoutArgs( CreateFunctor(ReceivePointer(mock.web_browser2_), &IWebBrowser::GoForward)))); @@ -556,14 +557,14 @@ TEST_F(ChromeFrameTestWithWebServer, FLAKY_FullTabModeIE_BackForwardAnchor) { // Back/Forward state at this point: // Back: 3 (kAnchorUrl, kAnchor1Url, kAnchor2Url) // Forward: 1 (kAnchor3Url) - EXPECT_CALL(mock, OnLoad(testing::StrEq(kAnchor2Url))) + EXPECT_CALL(mock, OnLoad(testing::StrCaseEq(kAnchor2Url))) .WillOnce(testing::IgnoreResult(testing::InvokeWithoutArgs( CreateFunctor(ReceivePointer(mock.web_browser2_), &IWebBrowser::GoForward)))); mock.ExpectNavigation(kAnchor3Url); // We have gone a few steps back and forward, this should be enough for now. - EXPECT_CALL(mock, OnLoad(testing::StrEq(kAnchor3Url))) + EXPECT_CALL(mock, OnLoad(testing::StrCaseEq(kAnchor3Url))) .WillOnce(testing::IgnoreResult(testing::InvokeWithoutArgs( CreateFunctor(&mock, &MockWebBrowserEventSink::CloseWebBrowser)))); @@ -592,7 +593,7 @@ TEST_F(ChromeFrameTestWithWebServer, FLAKY_FullTabModeIE_ViewSource) { mock.ExpectNavigationAndSwitchSequence(kAnchorUrl); VARIANT empty = ScopedVariant::kEmptyVariant; - EXPECT_CALL(mock, OnLoad(testing::StrEq(kAnchorUrl))) + EXPECT_CALL(mock, OnLoad(testing::StrCaseEq(kAnchorUrl))) .WillOnce(testing::InvokeWithoutArgs( CreateFunctor(&mock, &MockWebBrowserEventSink::Exec, &CGID_MSHTML, static_cast<OLECMDID>(IDM_VIEWSOURCE), @@ -609,7 +610,7 @@ TEST_F(ChromeFrameTestWithWebServer, FLAKY_FullTabModeIE_ViewSource) { ComStackObjectWithUninitialize<MockWebBrowserEventSink> view_source_mock; mock.ExpectNewWindow(&view_source_mock); - EXPECT_CALL(view_source_mock, OnLoad(testing::StrEq(view_source_url))) + EXPECT_CALL(view_source_mock, OnLoad(testing::StrCaseEq(view_source_url))) .WillOnce(testing::IgnoreResult(testing::InvokeWithoutArgs( CreateFunctor(&view_source_mock, &MockWebBrowserEventSink::CloseWebBrowser)))); @@ -732,7 +733,7 @@ TEST_F(ChromeFrameTestWithWebServer, // Navigate to url 2 after the previous navigation is complete. mock.ExpectNavigationAndSwitchSequence(kSubFrameUrl1); - EXPECT_CALL(mock, OnLoad(testing::StrEq(kSubFrameUrl1))) + EXPECT_CALL(mock, OnLoad(testing::StrCaseEq(kSubFrameUrl1))) .WillOnce(testing::IgnoreResult(testing::InvokeWithoutArgs( CreateFunctor(&mock, &chrome_frame_test::WebBrowserEventSink::Navigate, @@ -741,7 +742,7 @@ TEST_F(ChromeFrameTestWithWebServer, mock.ExpectNavigationAndSwitchSequence(kSubFrameUrl2); // Go back using Rt-Click + DOWN + ENTER - EXPECT_CALL(mock, OnLoad(testing::StrEq(kSubFrameUrl2))) + EXPECT_CALL(mock, OnLoad(testing::StrCaseEq(kSubFrameUrl2))) .WillOnce(testing::DoAll( testing::InvokeWithoutArgs(CreateFunctor(&mock, &MockWebBrowserEventSink::SendMouseClick, 10, 10, @@ -761,7 +762,7 @@ TEST_F(ChromeFrameTestWithWebServer, mock.ExpectNavigation(kSubFrameUrl1); // Go forward using Rt-Click + DOWN + DOWN + ENTER - EXPECT_CALL(mock, OnLoad(testing::StrEq(kSubFrameUrl1))) + EXPECT_CALL(mock, OnLoad(testing::StrCaseEq(kSubFrameUrl1))) .WillOnce(testing::DoAll( testing::InvokeWithoutArgs(CreateFunctor(&mock, &MockWebBrowserEventSink::SendMouseClick, 10, 10, @@ -786,7 +787,7 @@ TEST_F(ChromeFrameTestWithWebServer, mock.ExpectNavigation(kSubFrameUrl2); - EXPECT_CALL(mock, OnLoad(testing::StrEq(kSubFrameUrl2))) + EXPECT_CALL(mock, OnLoad(testing::StrCaseEq(kSubFrameUrl2))) .WillOnce(testing::IgnoreResult(testing::InvokeWithoutArgs( CreateFunctor(&mock, &MockWebBrowserEventSink::CloseWebBrowser)))); @@ -814,7 +815,7 @@ TEST_F(ChromeFrameTestWithWebServer, FLAKY_FullTabModeIE_ContextMenuReload) { mock.ExpectNavigationAndSwitchSequence(kSubFrameUrl1); // Reload using Rt-Click + DOWN + DOWN + DOWN + ENTER - EXPECT_CALL(mock, OnLoad(testing::StrEq(kSubFrameUrl1))) + EXPECT_CALL(mock, OnLoad(testing::StrCaseEq(kSubFrameUrl1))) .WillOnce(testing::DoAll( testing::InvokeWithoutArgs(CreateFunctor(&mock, &MockWebBrowserEventSink::SendMouseClick, 10, 10, @@ -843,7 +844,7 @@ TEST_F(ChromeFrameTestWithWebServer, FLAKY_FullTabModeIE_ContextMenuReload) { simulate_input::SendString<wchar_t>, &enter_key[0]), 800)))); - EXPECT_CALL(mock, OnLoad(testing::StrEq(kSubFrameUrl1))) + EXPECT_CALL(mock, OnLoad(testing::StrCaseEq(kSubFrameUrl1))) .WillOnce(testing::IgnoreResult(testing::InvokeWithoutArgs( CreateFunctor(&mock, &MockWebBrowserEventSink::CloseWebBrowser)))); @@ -867,9 +868,9 @@ TEST_F(ChromeFrameTestWithWebServer, ComStackObjectWithUninitialize<MockWebBrowserEventSink> mock; ::testing::InSequence sequence; // Everything in sequence - // view source using Rt-Click + UP + UP + UP + UP + ENTER + // View source using Rt-Click + UP + UP + UP + UP + ENTER mock.ExpectNavigationAndSwitchSequence(kAnchorUrl); - EXPECT_CALL(mock, OnLoad(testing::StrEq(kAnchorUrl))) + EXPECT_CALL(mock, OnLoad(testing::StrCaseEq(kAnchorUrl))) .WillOnce(testing::DoAll( testing::InvokeWithoutArgs(CreateFunctor(&mock, &MockWebBrowserEventSink::SendMouseClick, 10, 10, @@ -915,7 +916,7 @@ TEST_F(ChromeFrameTestWithWebServer, ComStackObjectWithUninitialize<MockWebBrowserEventSink> view_source_mock; mock.ExpectNewWindow(&view_source_mock); - EXPECT_CALL(view_source_mock, OnLoad(testing::StrEq(view_source_url))) + EXPECT_CALL(view_source_mock, OnLoad(testing::StrCaseEq(view_source_url))) .WillOnce(testing::IgnoreResult(testing::InvokeWithoutArgs( CreateFunctor(&view_source_mock, &MockWebBrowserEventSink::CloseWebBrowser)))); @@ -934,6 +935,227 @@ TEST_F(ChromeFrameTestWithWebServer, loop.RunFor(kChromeFrameLongNavigationTimeoutInSeconds); } +TEST_F(ChromeFrameTestWithWebServer, + FLAKY_FullTabModeIE_ContextMenuPageInfo) { + CloseIeAtEndOfScope last_resort_close_ie; + chrome_frame_test::TimedMsgLoop loop; + ComStackObjectWithUninitialize<MockWebBrowserEventSink> mock; + ::testing::InSequence sequence; // Everything in sequence + + // View page information using Rt-Click + UP + UP + UP + ENTER + const wchar_t* kPageInfoWindowClass = L"Chrome_WidgetWin_0"; + mock.ExpectNavigationAndSwitchSequence(kAnchorUrl); + EXPECT_CALL(mock, OnLoad(testing::StrCaseEq(kAnchorUrl))) + .WillOnce(testing::DoAll( + testing::InvokeWithoutArgs(CreateFunctor(&mock, + &MockWebBrowserEventSink::WatchChromeWindow, + kPageInfoWindowClass)), + testing::InvokeWithoutArgs(CreateFunctor(&mock, + &MockWebBrowserEventSink::SendMouseClick, 10, 10, + simulate_input::RIGHT)), + testing::InvokeWithoutArgs(CreateFunctor(&loop, + &chrome_frame_test::TimedMsgLoop::PostDelayedTask, FROM_HERE, + NewRunnableFunction( + simulate_input::SendExtendedKey, VK_UP, false, false, + false), + 500)), + testing::InvokeWithoutArgs(CreateFunctor(&loop, + &chrome_frame_test::TimedMsgLoop::PostDelayedTask, FROM_HERE, + NewRunnableFunction( + simulate_input::SendExtendedKey, VK_UP, false, false, + false), + 600)), + testing::InvokeWithoutArgs(CreateFunctor(&loop, + &chrome_frame_test::TimedMsgLoop::PostDelayedTask, FROM_HERE, + NewRunnableFunction( + simulate_input::SendExtendedKey, VK_UP, false, false, + false), + 700)), + testing::InvokeWithoutArgs(CreateFunctor(&loop, + &chrome_frame_test::TimedMsgLoop::PostDelayedTask, FROM_HERE, + NewRunnableFunction( + simulate_input::SendString<wchar_t>, &enter_key[0]), + 800)))); + + // Expect page info dialog to pop up. Dismiss the dialog with 'Esc' key + const char* kPageInfoCaption = "Security Information"; + EXPECT_CALL(mock, OnWindowDetected(_, testing::StrCaseEq(kPageInfoCaption))) + .WillOnce(testing::DoAll( + testing::WithArgs<0>(testing::Invoke( + simulate_input::SetKeyboardFocusToWindow)), + testing::InvokeWithoutArgs(CreateFunctor(&loop, + &chrome_frame_test::TimedMsgLoop::PostDelayedTask, FROM_HERE, + NewRunnableFunction( + simulate_input::SendString<wchar_t>, &escape_key[0]), + 100)), + testing::InvokeWithoutArgs(CreateFunctor(&loop, + &chrome_frame_test::TimedMsgLoop::PostDelayedTask, FROM_HERE, + NewRunnableMethod(&mock, + &MockWebBrowserEventSink::CloseWebBrowser), + 600)))); + + EXPECT_CALL(mock, OnQuit()).WillOnce(QUIT_LOOP(loop)); + + HRESULT hr = mock.LaunchIEAndNavigate(kAnchorUrl); + ASSERT_HRESULT_SUCCEEDED(hr); + if (hr == S_FALSE) + return; + + ASSERT_TRUE(mock.web_browser2() != NULL); + loop.RunFor(kChromeFrameLongNavigationTimeoutInSeconds); +} + +TEST_F(ChromeFrameTestWithWebServer, + FLAKY_FullTabModeIE_ContextMenuInspector) { + CloseIeAtEndOfScope last_resort_close_ie; + chrome_frame_test::TimedMsgLoop loop; + ComStackObjectWithUninitialize<MockWebBrowserEventSink> mock; + ::testing::InSequence sequence; // Everything in sequence + + // Open developer tools using Rt-Click + UP + UP + ENTER + const wchar_t* kPageInfoWindowClass = L"Chrome_WidgetWin_0"; + mock.ExpectNavigationAndSwitchSequence(kAnchorUrl); + EXPECT_CALL(mock, OnLoad(testing::StrCaseEq(kAnchorUrl))) + .WillOnce(testing::DoAll( + testing::InvokeWithoutArgs(CreateFunctor(&mock, + &MockWebBrowserEventSink::WatchChromeWindow, + kPageInfoWindowClass)), + testing::InvokeWithoutArgs(CreateFunctor(&mock, + &MockWebBrowserEventSink::SendMouseClick, 10, 10, + simulate_input::RIGHT)), + testing::InvokeWithoutArgs(CreateFunctor(&loop, + &chrome_frame_test::TimedMsgLoop::PostDelayedTask, FROM_HERE, + NewRunnableFunction( + simulate_input::SendExtendedKey, VK_UP, false, false, + false), + 500)), + testing::InvokeWithoutArgs(CreateFunctor(&loop, + &chrome_frame_test::TimedMsgLoop::PostDelayedTask, FROM_HERE, + NewRunnableFunction( + simulate_input::SendExtendedKey, VK_UP, false, false, + false), + 600)), + testing::InvokeWithoutArgs(CreateFunctor(&loop, + &chrome_frame_test::TimedMsgLoop::PostDelayedTask, FROM_HERE, + NewRunnableFunction( + simulate_input::SendString<wchar_t>, &enter_key[0]), + 800)))); + + // Devtools begins life with "Untitled" caption and it changes + // later to the 'Developer Tools - <url> form. + const char* kPageInfoCaption = "Untitled"; + EXPECT_CALL(mock, OnWindowDetected(_, testing::StartsWith(kPageInfoCaption))) + .WillOnce(testing::DoAll( + testing::InvokeWithoutArgs(CreateFunctor(&mock, + &MockWebBrowserEventSink::StopWatching)), + testing::WithArgs<0>(testing::Invoke( + simulate_input::SetKeyboardFocusToWindow)), + testing::InvokeWithoutArgs(CreateFunctor(&loop, + &chrome_frame_test::TimedMsgLoop::PostDelayedTask, FROM_HERE, + NewRunnableMethod(&mock, + &MockWebBrowserEventSink::CloseWebBrowser), + 2000)))); + + EXPECT_CALL(mock, OnQuit()).WillOnce(QUIT_LOOP(loop)); + + HRESULT hr = mock.LaunchIEAndNavigate(kAnchorUrl); + ASSERT_HRESULT_SUCCEEDED(hr); + if (hr == S_FALSE) + return; + + ASSERT_TRUE(mock.web_browser2() != NULL); + loop.RunFor(kChromeFrameLongNavigationTimeoutInSeconds); +} + +TEST_F(ChromeFrameTestWithWebServer, + FLAKY_FullTabModeIE_ContextMenuSaveAs) { + CloseIeAtEndOfScope last_resort_close_ie; + chrome_frame_test::TimedMsgLoop loop; + ComStackObjectWithUninitialize<MockWebBrowserEventSink> mock; + ::testing::InSequence sequence; // Everything in sequence + + // Open'Save As' dialog using Rt-Click + DOWN + DOWN + DOWN + DOWN + ENTER + const wchar_t* kSaveDlgClass = L"#32770"; + mock.ExpectNavigationAndSwitchSequence(kAnchorUrl); + EXPECT_CALL(mock, OnLoad(testing::StrCaseEq(kAnchorUrl))) + .WillOnce(testing::DoAll( + testing::InvokeWithoutArgs(CreateFunctor(&mock, + &MockWebBrowserEventSink::WatchChromeWindow, + kSaveDlgClass)), + testing::InvokeWithoutArgs(CreateFunctor(&mock, + &MockWebBrowserEventSink::SendMouseClick, 10, 10, + simulate_input::RIGHT)), + testing::InvokeWithoutArgs(CreateFunctor(&loop, + &chrome_frame_test::TimedMsgLoop::PostDelayedTask, FROM_HERE, + NewRunnableFunction( + simulate_input::SendExtendedKey, VK_DOWN, false, false, + false), + 500)), + testing::InvokeWithoutArgs(CreateFunctor(&loop, + &chrome_frame_test::TimedMsgLoop::PostDelayedTask, FROM_HERE, + NewRunnableFunction( + simulate_input::SendExtendedKey, VK_DOWN, false, false, + false), + 600)), + testing::InvokeWithoutArgs(CreateFunctor(&loop, + &chrome_frame_test::TimedMsgLoop::PostDelayedTask, FROM_HERE, + NewRunnableFunction( + simulate_input::SendExtendedKey, VK_DOWN, false, false, + false), + 700)), + testing::InvokeWithoutArgs(CreateFunctor(&loop, + &chrome_frame_test::TimedMsgLoop::PostDelayedTask, FROM_HERE, + NewRunnableFunction( + simulate_input::SendExtendedKey, VK_DOWN, false, false, + false), + 800)), + testing::InvokeWithoutArgs(CreateFunctor(&loop, + &chrome_frame_test::TimedMsgLoop::PostDelayedTask, FROM_HERE, + NewRunnableFunction( + simulate_input::SendString<wchar_t>, &enter_key[0]), + 900)))); + + FilePath temp_file_path; + EXPECT_TRUE(file_util::CreateTemporaryFile(&temp_file_path)); + + const wchar_t* kSaveFileName = temp_file_path.value().c_str(); + const char* kSaveDlgCaption = "Save As"; + EXPECT_CALL(mock, OnWindowDetected(_, testing::StrCaseEq(kSaveDlgCaption))) + .WillOnce(testing::DoAll( + testing::InvokeWithoutArgs(CreateFunctor(&mock, + &MockWebBrowserEventSink::StopWatching)), + testing::WithArgs<0>(testing::Invoke( + simulate_input::SetKeyboardFocusToWindow)), + testing::InvokeWithoutArgs(CreateFunctor(&loop, + &chrome_frame_test::TimedMsgLoop::PostDelayedTask, FROM_HERE, + NewRunnableFunction( + simulate_input::SendString<wchar_t>, kSaveFileName), + 100)), + testing::InvokeWithoutArgs(CreateFunctor(&loop, + &chrome_frame_test::TimedMsgLoop::PostDelayedTask, FROM_HERE, + NewRunnableFunction( + simulate_input::SendString<wchar_t>, &enter_key[0]), + 200)), + testing::InvokeWithoutArgs(CreateFunctor(&loop, + &chrome_frame_test::TimedMsgLoop::PostDelayedTask, FROM_HERE, + NewRunnableMethod(&mock, + &MockWebBrowserEventSink::CloseWebBrowser), + 4000)))); + + EXPECT_CALL(mock, OnQuit()).WillOnce(QUIT_LOOP(loop)); + + HRESULT hr = mock.LaunchIEAndNavigate(kAnchorUrl); + ASSERT_HRESULT_SUCCEEDED(hr); + if (hr == S_FALSE) + return; + + ASSERT_TRUE(mock.web_browser2() != NULL); + loop.RunFor(kChromeFrameLongNavigationTimeoutInSeconds); + + ASSERT_NE(INVALID_FILE_ATTRIBUTES, GetFileAttributes(kSaveFileName)); + ASSERT_TRUE(DeleteFile(kSaveFileName)); +} + // Marking this test FLAKY as it fails at times on the buildbot. // http://code.google.com/p/chromium/issues/detail?id=26549 TEST_F(ChromeFrameTestWithWebServer, @@ -953,14 +1175,14 @@ TEST_F(ChromeFrameTestWithWebServer, // 4. Sends the Shift + VK_BACK keystroke to IE which should navigate // forward to http://localhost:1337/files/sub_frame2.html mock.ExpectNavigationAndSwitchSequence(kSubFrameUrl1); - EXPECT_CALL(mock, OnLoad(testing::StrEq(kSubFrameUrl1))) + EXPECT_CALL(mock, OnLoad(testing::StrCaseEq(kSubFrameUrl1))) .WillOnce(testing::IgnoreResult(testing::InvokeWithoutArgs( CreateFunctor( &mock, &chrome_frame_test::WebBrowserEventSink::Navigate, std::wstring(kSubFrameUrl2))))); mock.ExpectNavigationAndSwitchSequence(kSubFrameUrl2); - EXPECT_CALL(mock, OnLoad(testing::StrEq(kSubFrameUrl2))) + EXPECT_CALL(mock, OnLoad(testing::StrCaseEq(kSubFrameUrl2))) .WillOnce(testing::InvokeWithoutArgs(CreateFunctor(&loop, &chrome_frame_test::TimedMsgLoop::PostDelayedTask, FROM_HERE, NewRunnableMethod( @@ -968,7 +1190,7 @@ TEST_F(ChromeFrameTestWithWebServer, &MockWebBrowserEventSink::NavigateBackward), 500))); mock.ExpectNavigation(kSubFrameUrl1); - EXPECT_CALL(mock, OnLoad(testing::StrEq(kSubFrameUrl1))) + EXPECT_CALL(mock, OnLoad(testing::StrCaseEq(kSubFrameUrl1))) .WillOnce(testing::InvokeWithoutArgs(CreateFunctor(&loop, &chrome_frame_test::TimedMsgLoop::PostDelayedTask, FROM_HERE, NewRunnableMethod( @@ -976,7 +1198,7 @@ TEST_F(ChromeFrameTestWithWebServer, &MockWebBrowserEventSink::NavigateForward), 500))); mock.ExpectNavigation(kSubFrameUrl2); - EXPECT_CALL(mock, OnLoad(testing::StrEq(kSubFrameUrl2))) + EXPECT_CALL(mock, OnLoad(testing::StrCaseEq(kSubFrameUrl2))) .Times(1) .WillOnce(QUIT_LOOP_SOON(loop, 2)); diff --git a/chrome_frame/test/test_mock_with_web_server.h b/chrome_frame/test/test_mock_with_web_server.h index 5550837..fd21c99 100644 --- a/chrome_frame/test/test_mock_with_web_server.h +++ b/chrome_frame/test/test_mock_with_web_server.h @@ -65,13 +65,15 @@ class MockWebBrowserEventSink : public chrome_frame_test::WebBrowserEventSink { MOCK_METHOD0_WITH_CALLTYPE(__stdcall, OnQuit, void ()); - MOCK_METHOD1(OnLoad, void (const wchar_t* url)); // NOLINT - MOCK_METHOD1(OnLoadError, void (const wchar_t* url)); // NOLINT + MOCK_METHOD1(OnLoad, void (const wchar_t* url)); // NOLINT + MOCK_METHOD1(OnLoadError, void (const wchar_t* url)); // NOLINT MOCK_METHOD3(OnMessage, void (const wchar_t* message, const wchar_t* origin, - const wchar_t* source)); // NOLINT + const wchar_t* source)); // NOLINT MOCK_METHOD2(OnNewBrowserWindow, void (IDispatch* dispatch, // NOLINT const wchar_t* url)); + MOCK_METHOD2(OnWindowDetected, void (HWND hwnd, // NOLINT + const std::string& caption)); // Test expectations ExpectationSet ExpectNavigationCardinality(const std::wstring& url, diff --git a/chrome_frame/test/window_watchdog.cc b/chrome_frame/test/window_watchdog.cc new file mode 100644 index 0000000..b388c0a --- /dev/null +++ b/chrome_frame/test/window_watchdog.cc @@ -0,0 +1,89 @@ +// 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/test/window_watchdog.h" + +#include "base/logging.h" +#include "base/string_util.h" + +#include "chrome_frame/function_stub.h" + + +WindowWatchdog::WindowWatchdog() : hook_(NULL), hook_stub_(NULL) { +} + +WindowWatchdog::~WindowWatchdog() { + UninitializeHook(); +} + +void WindowWatchdog::AddObserver(WindowObserver* observer, + const std::string& window_class) { + WindowObserverEntry new_entry = { observer, window_class }; + observers_.push_back(new_entry); + + if (!hook_) + InitializeHook(); +} + +void WindowWatchdog::RemoveObserver(WindowObserver* observer) { + for (ObserverMap::iterator i = observers_.begin(); i != observers_.end();) { + i = (observer = i->observer) ? observers_.erase(i) : ++i; + } + + if (observers_.empty()) + UninitializeHook(); +} + +bool WindowWatchdog::InitializeHook() { + DCHECK(hook_ == NULL); + DCHECK(hook_stub_ == NULL); + hook_stub_ = FunctionStub::Create(reinterpret_cast<uintptr_t>(this), + WinEventHook); + hook_ = SetWinEventHook(EVENT_OBJECT_SHOW, EVENT_OBJECT_SHOW, NULL, + reinterpret_cast<WINEVENTPROC>(hook_stub_->code()), 0, + 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS); + + return hook_ != NULL; +} + +void WindowWatchdog::UninitializeHook() { + if (hook_) { + ::UnhookWinEvent(hook_); + hook_ = NULL; + FunctionStub::Destroy(hook_stub_); + hook_stub_ = NULL; + } +} + +// static +void WindowWatchdog::WinEventHook(WindowWatchdog* me, HWINEVENTHOOK hook, + DWORD event, HWND hwnd, LONG object_id, + LONG child_id, DWORD event_thread_id, + DWORD event_time) { + // We need to look for top level windows and a natural check is for + // WS_CHILD. Instead, checking for WS_CAPTION allows us to filter + // out other stray popups + if (!(WS_CAPTION & GetWindowLong(hwnd, GWL_STYLE))) + return; + + char class_name[MAX_PATH] = {0}; + ::GetClassNameA(hwnd, class_name, arraysize(class_name)); + + ObserverMap interested_observers; + for (ObserverMap::iterator i = me->observers_.begin(); + i != me->observers_.end(); i++) { + if (0 == lstrcmpA(i->window_class.c_str(), class_name)) { + interested_observers.push_back(*i); + } + } + + std::string caption; + int len = ::GetWindowTextLength(hwnd) + 1; + ::GetWindowTextA(hwnd, WriteInto(&caption, len), len); + + for (ObserverMap::iterator i = interested_observers.begin(); + i != interested_observers.end(); i++) { + i->observer->OnWindowDetected(hwnd, caption); + } +} diff --git a/chrome_frame/test/window_watchdog.h b/chrome_frame/test/window_watchdog.h new file mode 100644 index 0000000..700859f --- /dev/null +++ b/chrome_frame/test/window_watchdog.h @@ -0,0 +1,60 @@ +// 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. + +#ifndef CHROME_FRAME_TEST_WINDOW_WATCHDOG_H_ +#define CHROME_FRAME_TEST_WINDOW_WATCHDOG_H_ + +#include <windows.h> + +#include <string> +#include <vector> + +struct FunctionStub; + +// Interface implemented by WindowWatchdog users. An observer can register +// for notifications on multiple window classes. +class WindowObserver { // NOLINT + public: + virtual void OnWindowDetected(HWND hwnd, const std::string& caption) = 0; +}; + +// Watch a for window to be shown with the given window class name. +// If found, call the observer interested in it. +class WindowWatchdog { + public: + WindowWatchdog(); + ~WindowWatchdog(); + + // Register for notifications for |window_class|. An observer can register + // for multiple notifications + void AddObserver(WindowObserver* observer, const std::string& window_class); + + // Remove all entries for |observer| + void RemoveObserver(WindowObserver* observer); + + protected: + bool InitializeHook(); + void UninitializeHook(); + + static void CALLBACK WinEventHook(WindowWatchdog* me, HWINEVENTHOOK hook, + DWORD event, HWND hwnd, LONG object_id, LONG child_id, + DWORD event_thread_id, DWORD event_time); + + void OnDialogFound(HWND hwnd, const std::string& caption); + + protected: + struct WindowObserverEntry { + WindowObserver* observer; + std::string window_class; + }; + + typedef std::vector<WindowObserverEntry> ObserverMap; + + HWINEVENTHOOK hook_; + ObserverMap observers_; + FunctionStub* hook_stub_; +}; + + +#endif // CHROME_FRAME_TEST_WINDOW_WATCHDOG_H_ |