summaryrefslogtreecommitdiffstats
path: root/chrome_frame
diff options
context:
space:
mode:
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_