summaryrefslogtreecommitdiffstats
path: root/chrome_frame
diff options
context:
space:
mode:
authoramit@chromium.org <amit@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-04 21:18:52 +0000
committeramit@chromium.org <amit@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-04 21:18:52 +0000
commite0b421291b0644eebf04660d993995e638251bf0 (patch)
tree8eb9ab232ab852e38625f3c79032f3e4209b5806 /chrome_frame
parent66a7e419553da5367d5f143fd0a975b25e1b1726 (diff)
downloadchromium_src-e0b421291b0644eebf04660d993995e638251bf0.zip
chromium_src-e0b421291b0644eebf04660d993995e638251bf0.tar.gz
chromium_src-e0b421291b0644eebf04660d993995e638251bf0.tar.bz2
More context menu tests
Refactored code to monitor windows so that it could be used with our mock to watch for dialogs and chrome windows. Added new tests for 'Page Info', 'Dev Tools' and 'Save As' menu options. BUG=34673 TESTS=newly added Review URL: http://codereview.chromium.org/667005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@40654 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome_frame')
-rw-r--r--chrome_frame/chrome_frame.gyp8
-rw-r--r--chrome_frame/test/chrome_frame_test_utils.cc9
-rw-r--r--chrome_frame/test/chrome_frame_test_utils.h65
-rw-r--r--chrome_frame/test/net/dialog_watchdog.cc146
-rw-r--r--chrome_frame/test/net/dialog_watchdog.h64
-rw-r--r--chrome_frame/test/net/fake_external_tab.cc104
-rw-r--r--chrome_frame/test/simulate_input.cc20
-rw-r--r--chrome_frame/test/simulate_input.h3
-rw-r--r--chrome_frame/test/test_mock_with_web_server.cc288
-rw-r--r--chrome_frame/test/test_mock_with_web_server.h8
-rw-r--r--chrome_frame/test/window_watchdog.cc89
-rw-r--r--chrome_frame/test/window_watchdog.h60
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_