summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome_frame/test/chrome_frame_test_utils.cc52
-rw-r--r--chrome_frame/test/chrome_frame_test_utils.h55
-rwxr-xr-xchrome_frame/test/data/no_interference/empty.html0
-rw-r--r--chrome_frame/test/data/no_interference/window_open.html12
-rw-r--r--chrome_frame/test/no_interference_test.cc129
-rw-r--r--chrome_frame/test/test_mock_with_web_server.cc65
-rw-r--r--chrome_frame/test/test_mock_with_web_server.h8
-rw-r--r--chrome_frame/test/test_with_web_server.cc4
8 files changed, 256 insertions, 69 deletions
diff --git a/chrome_frame/test/chrome_frame_test_utils.cc b/chrome_frame/test/chrome_frame_test_utils.cc
index 1cc1f47..5b60922 100644
--- a/chrome_frame/test/chrome_frame_test_utils.cc
+++ b/chrome_frame/test/chrome_frame_test_utils.cc
@@ -14,6 +14,7 @@
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/registry.h" // to find IE and firefox
+#include "base/scoped_bstr_win.h"
#include "base/scoped_handle.h"
#include "base/scoped_comptr_win.h"
#include "base/utf_string_conversions.h"
@@ -37,6 +38,7 @@ const wchar_t kSafariImageName[] = L"safari.exe";
const wchar_t kChromeImageName[] = L"chrome.exe";
const wchar_t kIEProfileName[] = L"iexplore";
const wchar_t kChromeLauncher[] = L"chrome_launcher.exe";
+const int kChromeFrameLongNavigationTimeoutInSeconds = 10;
// Callback function for EnumThreadWindows.
BOOL CALLBACK CloseWindowsThreadCallback(HWND hwnd, LPARAM param) {
@@ -667,6 +669,11 @@ void WebBrowserEventSink::SendMouseClick(int x, int y,
simulate_input::SendMouseClick(GetRendererWindow(), x, y, button);
}
+void WebBrowserEventSink::SendMouseClickToIE(int x, int y,
+ simulate_input::MouseButton button) {
+ simulate_input::SendMouseClick(GetIERendererWindow(), x, y, button);
+}
+
void WebBrowserEventSink::ConnectToChromeFrame() {
DCHECK(web_browser2_);
if (chrome_frame_.get())
@@ -730,6 +737,24 @@ HWND WebBrowserEventSink::GetRendererWindow() {
return renderer_window;
}
+HWND WebBrowserEventSink::GetIERendererWindow() {
+ DCHECK(web_browser2_);
+ HWND renderer_window = NULL;
+ ScopedComPtr<IDispatch> doc;
+ HRESULT hr = web_browser2_->get_Document(doc.Receive());
+ EXPECT_HRESULT_SUCCEEDED(hr);
+ EXPECT_TRUE(doc);
+ if (doc) {
+ ScopedComPtr<IOleWindow> ole_window;
+ ole_window.QueryFrom(doc);
+ EXPECT_TRUE(ole_window);
+ if (ole_window) {
+ ole_window->GetWindow(&renderer_window);
+ }
+ }
+ return renderer_window;
+}
+
HRESULT WebBrowserEventSink::SetWebBrowser(IWebBrowser2* web_browser2) {
DCHECK(web_browser2_.get() == NULL);
DCHECK(!is_main_browser_object_);
@@ -749,7 +774,7 @@ HRESULT WebBrowserEventSink::CloseWebBrowser() {
return S_OK;
}
-void WebBrowserEventSink::ExpectRendererWindowHasfocus() {
+void WebBrowserEventSink::ExpectRendererWindowHasFocus() {
HWND renderer_window = GetRendererWindow();
EXPECT_TRUE(IsWindow(renderer_window));
@@ -773,6 +798,31 @@ void WebBrowserEventSink::ExpectRendererWindowHasfocus() {
EXPECT_TRUE(AttachThreadInput(GetCurrentThreadId(), renderer_thread, FALSE));
}
+void WebBrowserEventSink::ExpectIERendererWindowHasFocus() {
+ HWND renderer_window = GetIERendererWindow();
+ EXPECT_TRUE(IsWindow(renderer_window));
+
+ DWORD renderer_thread = 0;
+ DWORD renderer_process = 0;
+ renderer_thread = GetWindowThreadProcessId(renderer_window,
+ &renderer_process);
+
+ ASSERT_TRUE(AttachThreadInput(GetCurrentThreadId(), renderer_thread, TRUE));
+ HWND focus_window = GetFocus();
+ EXPECT_TRUE(focus_window == renderer_window);
+ EXPECT_TRUE(AttachThreadInput(GetCurrentThreadId(), renderer_thread, FALSE));
+}
+
+void WebBrowserEventSink::ExpectAddressBarUrl(
+ const std::wstring& expected_url) {
+ DCHECK(web_browser2_);
+ if (web_browser2_) {
+ ScopedBstr address_bar_url;
+ EXPECT_EQ(S_OK, web_browser2_->get_LocationURL(address_bar_url.Receive()));
+ EXPECT_EQ(expected_url, std::wstring(address_bar_url));
+ }
+}
+
void WebBrowserEventSink::Exec(const GUID* cmd_group_guid, DWORD command_id,
DWORD cmd_exec_opt, VARIANT* in_args,
VARIANT* out_args) {
diff --git a/chrome_frame/test/chrome_frame_test_utils.h b/chrome_frame/test/chrome_frame_test_utils.h
index 5a4e841..717b204 100644
--- a/chrome_frame/test/chrome_frame_test_utils.h
+++ b/chrome_frame/test/chrome_frame_test_utils.h
@@ -53,6 +53,7 @@ extern const wchar_t kOperaImageName[];
extern const wchar_t kSafariImageName[];
extern const wchar_t kChromeImageName[];
extern const wchar_t kChromeLauncher[];
+extern const int kChromeFrameLongNavigationTimeoutInSeconds;
// Temporarily impersonate the current thread to low integrity for the lifetime
// of the object. Destructor will automatically revert integrity level.
@@ -106,10 +107,10 @@ class TimedMsgLoop {
// testing::InvokeWithoutArgs since it returns a
// non-public (testing::internal) type.
#define QUIT_LOOP(loop) testing::InvokeWithoutArgs(\
- CreateFunctor(&loop, &chrome_frame_test::TimedMsgLoop::Quit))
+ testing::CreateFunctor(&loop, &chrome_frame_test::TimedMsgLoop::Quit))
#define QUIT_LOOP_SOON(loop, seconds) testing::InvokeWithoutArgs(\
- CreateFunctor(&loop, &chrome_frame_test::TimedMsgLoop::QuitAfter, \
+ testing::CreateFunctor(&loop, &chrome_frame_test::TimedMsgLoop::QuitAfter, \
seconds))
// Launches IE as a COM server and returns the corresponding IWebBrowser2
@@ -194,21 +195,25 @@ END_SINK_MAP()
void SetFocusToChrome();
// Send keyboard input to the renderer window hosted in chrome using
- // SendInput API
+ // SendInput API.
void SendKeys(const wchar_t* input_string);
// Send mouse click to the renderer window hosted in chrome using
- // SendInput API
+ // SendInput API.
void SendMouseClick(int x, int y, simulate_input::MouseButton button);
+ // Send mouse click to the renderer window hosted in IE using
+ // SendInput API.
+ void SendMouseClickToIE(int x, int y, simulate_input::MouseButton button);
+
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
+ // Watch for new window created.
void WatchChromeWindow(const wchar_t* window_class);
void StopWatching();
- // Overridable methods for the mock
+ // Overridable methods for the mock.
STDMETHOD_(void, OnNavigateError)(IDispatch* dispatch, VARIANT* url,
VARIANT* frame_name, VARIANT* status_code,
VARIANT* cancel) {
@@ -270,7 +275,9 @@ END_SINK_MAP()
}
HRESULT SetWebBrowser(IWebBrowser2* web_browser2);
- void ExpectRendererWindowHasfocus();
+ void ExpectRendererWindowHasFocus();
+ void ExpectIERendererWindowHasFocus();
+ void ExpectAddressBarUrl(const std::wstring& url);
// Closes the web browser in such a way that the OnQuit notification will
// be fired when the window closes (async).
@@ -298,6 +305,7 @@ END_SINK_MAP()
void ConnectToChromeFrame();
void DisconnectFromChromeFrame();
HWND GetRendererWindow();
+ HWND GetIERendererWindow();
public:
ScopedComPtr<IWebBrowser2> web_browser2_;
@@ -337,6 +345,39 @@ std::wstring GetExeVersion(const std::wstring& exe_path);
// Returns the version of Internet Explorer on the machine.
IEVersion GetInstalledIEVersion();
+// A convenience class to close all open IE windows at the end
+// of a scope. It's more convenient to do it this way than to
+// explicitly call chrome_frame_test::CloseAllIEWindows at the
+// end of a test since part of the test's cleanup code may be
+// in object destructors that would run after CloseAllIEWindows
+// would get called.
+// Ideally all IE windows should be closed when this happens so
+// if the test ran normally, we should not have any windows to
+// close at this point.
+class CloseIeAtEndOfScope {
+ public:
+ CloseIeAtEndOfScope() {}
+ ~CloseIeAtEndOfScope() {
+ int closed = CloseAllIEWindows();
+ DLOG_IF(ERROR, closed != 0)
+ << StringPrintf("Closed %i windows forcefully", closed);
+ }
+};
+
+// Specialization of CComObjectStackEx that performs object cleanup via
+// calling Base::Uninitialize() before we get to CComObjectStackEx' destructor.
+// The CComObjectStackEx destructor expects the reference count to be 0
+// or it will throw an assert. To work around that and to avoid having to
+// explicitly call Uninitialize() at the end of every test, we override the
+// destructor here to perform the cleanup.
+template <class Base>
+class ComStackObjectWithUninitialize : public CComObjectStackEx<Base> {
+ public:
+ virtual ~ComStackObjectWithUninitialize() {
+ Base::Uninitialize();
+ }
+};
+
} // namespace chrome_frame_test
#endif // CHROME_FRAME_TEST_CHROME_FRAME_TEST_UTILS_H_
diff --git a/chrome_frame/test/data/no_interference/empty.html b/chrome_frame/test/data/no_interference/empty.html
new file mode 100755
index 0000000..e69de29
--- /dev/null
+++ b/chrome_frame/test/data/no_interference/empty.html
diff --git a/chrome_frame/test/data/no_interference/window_open.html b/chrome_frame/test/data/no_interference/window_open.html
new file mode 100644
index 0000000..b426b17
--- /dev/null
+++ b/chrome_frame/test/data/no_interference/window_open.html
@@ -0,0 +1,12 @@
+<html>
+ <head>
+ <script type="text/javascript">
+ window.onload = function() {
+ window.open("empty.html", "test");
+ }
+ </script>
+ </head>
+ <body>
+ Calling window.open...
+ </body>
+</html> \ No newline at end of file
diff --git a/chrome_frame/test/no_interference_test.cc b/chrome_frame/test/no_interference_test.cc
new file mode 100644
index 0000000..acd1d5c
--- /dev/null
+++ b/chrome_frame/test/no_interference_test.cc
@@ -0,0 +1,129 @@
+// 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/test_mock_with_web_server.h"
+
+#include "base/scoped_variant_win.h"
+#include "base/utf_string_conversions.h"
+#include "chrome_frame/test/simulate_input.h"
+#include "chrome_frame/test/test_with_web_server.h"
+
+using chrome_frame_test::CloseIeAtEndOfScope;
+using chrome_frame_test::ComStackObjectWithUninitialize;
+using chrome_frame_test::kChromeFrameLongNavigationTimeoutInSeconds;
+using testing::_;
+
+namespace {
+
+// The same as MockWebBrowserEventSink, except OnDocumentComplete is added.
+// This class can be merged with its base class, but it would require some
+// modification to most of the test cases.
+class MockWebBrowserEventSink
+ : public chrome_frame_test::MockWebBrowserEventSink {
+ public:
+ // This method is called for each OnDocumentComplete event in which the
+ // document is rendered by IE and not CF.
+ MOCK_METHOD1(OnIELoad, void (const wchar_t* url)); // NOLINT
+
+ // The OnDocumentComplete event is received for every document load,
+ // regardless of whether IE or CF is hosting. This method will call
+ // OnIELoad iff the document was loaded in an IE renderer.
+ STDMETHOD_(void, OnDocumentComplete)(IDispatch* dispatch,
+ VARIANT* url_variant) {
+ ScopedVariant url;
+ if (url_variant)
+ url.Reset(*url_variant);
+ // To determine if the document is loaded in IE or CF, check if
+ // IHTMLDocument2 can be retrieved. If so, call OnIELoad.
+ ScopedComPtr<IWebBrowser2> web_browser2;
+ web_browser2.QueryFrom(dispatch);
+ EXPECT_TRUE(web_browser2);
+ if (web_browser2) {
+ ScopedComPtr<IDispatch> doc_dispatch;
+ HRESULT hr = web_browser2->get_Document(doc_dispatch.Receive());
+ EXPECT_HRESULT_SUCCEEDED(hr);
+ EXPECT_TRUE(doc_dispatch);
+ if (doc_dispatch) {
+ ScopedComPtr<IHTMLDocument2> doc;
+ doc.QueryFrom(doc_dispatch);
+ if (doc) {
+ OnIELoad(V_BSTR(&url));
+ }
+ }
+ }
+ }
+};
+
+// Fixture for tests which ensure that Chrome Frame does not interfere with
+// normal IE operation.
+// TODO(kkania): Move this fixture to test_mock_with_web_server.h and change
+// those tests to use this too.
+class NoInterferenceTest : public ChromeFrameTestWithWebServer {
+ protected:
+ // Launches IE and navigates to |url|, then waits until receiving a quit
+ // message or the timeout is exceeded.
+ void LaunchIEAndNavigate(const std::wstring& url) {
+ CloseIeAtEndOfScope last_resort_close_ie;
+
+ EXPECT_CALL(mock_, OnQuit())
+ .Times(testing::AtMost(1))
+ .WillOnce(QUIT_LOOP(loop_));
+ HRESULT hr = mock_.LaunchIEAndNavigate(url);
+ ASSERT_HRESULT_SUCCEEDED(hr);
+ if (hr == S_FALSE)
+ return;
+
+ ASSERT_TRUE(mock_.web_browser2() != NULL);
+ loop_.RunFor(kChromeFrameLongNavigationTimeoutInSeconds);
+ }
+
+ const std::wstring GetTestUrl(const wchar_t* relative_path) {
+ std::wstring path = std::wstring(L"files/no_interference/") +
+ relative_path;
+ return UTF8ToWide(server_.Resolve(path.c_str()).spec());
+ }
+
+ chrome_frame_test::TimedMsgLoop loop_;
+ ComStackObjectWithUninitialize<
+ testing::StrictMock<MockWebBrowserEventSink> > mock_;
+};
+
+ACTION_P(ExpectIERendererWindowHasFocus, mock) {
+ mock->ExpectIERendererWindowHasFocus();
+}
+
+// This tests that a new IE renderer window has focus.
+TEST_F(NoInterferenceTest, SimpleFocus) {
+ const std::wstring kEmptyFileUrl = GetTestUrl(L"empty.html");
+ mock_.ExpectNavigationAndSwitch(kEmptyFileUrl);
+
+ EXPECT_CALL(mock_, OnIELoad(testing::StrCaseEq(kEmptyFileUrl)))
+ .WillOnce(testing::DoAll(
+ ExpectIERendererWindowHasFocus(&mock_),
+ VerifyAddressBarUrl(&mock_),
+ CloseBrowserMock(&mock_)));
+
+ LaunchIEAndNavigate(kEmptyFileUrl);
+}
+
+// This tests that window.open does not get intercepted by Chrome Frame.
+TEST_F(NoInterferenceTest, FLAKY_JavascriptWindowOpen) {
+ const std::wstring kEmptyFileUrl = GetTestUrl(L"empty.html");
+ const std::wstring kWindowOpenUrl = GetTestUrl(L"window_open.html");
+ ComStackObjectWithUninitialize<
+ testing::StrictMock<MockWebBrowserEventSink> > new_window_mock;
+
+ mock_.ExpectNavigationAndSwitch(kWindowOpenUrl);
+ EXPECT_CALL(mock_, OnIELoad(testing::StrCaseEq(kWindowOpenUrl)));
+
+ mock_.ExpectNewWindow(&new_window_mock);
+ EXPECT_CALL(new_window_mock, OnIELoad(testing::StrCaseEq(kEmptyFileUrl)))
+ .WillOnce(CloseBrowserMock(&new_window_mock));
+ EXPECT_CALL(new_window_mock, OnQuit())
+ .WillOnce(CloseBrowserMock(&mock_));
+
+ LaunchIEAndNavigate(kWindowOpenUrl);
+}
+
+} // namespace \ No newline at end of file
diff --git a/chrome_frame/test/test_mock_with_web_server.cc b/chrome_frame/test/test_mock_with_web_server.cc
index 0b7ce1e..f869bb7 100644
--- a/chrome_frame/test/test_mock_with_web_server.cc
+++ b/chrome_frame/test/test_mock_with_web_server.cc
@@ -14,51 +14,18 @@
#define GMOCK_MUTANT_INCLUDE_LATE_OBJECT_BINDING
#include "testing/gmock_mutant.h"
-using testing::CreateFunctor;
using testing::_;
+using testing::CreateFunctor;
+using chrome_frame_test::CloseIeAtEndOfScope;
+using chrome_frame_test::ComStackObjectWithUninitialize;
+using chrome_frame_test::kChromeFrameLongNavigationTimeoutInSeconds;
using chrome_frame_test::MockWebBrowserEventSink;
-const int kChromeFrameLaunchDelay = 5;
-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
-// of a scope. It's more convenient to do it this way than to
-// explicitly call chrome_frame_test::CloseAllIEWindows at the
-// end of a test since part of the test's cleanup code may be
-// in object destructors that would run after CloseAllIEWindows
-// would get called.
-// Ideally all IE windows should be closed when this happens so
-// if the test ran normally, we should not have any windows to
-// close at this point.
-class CloseIeAtEndOfScope {
- public:
- CloseIeAtEndOfScope() {}
- ~CloseIeAtEndOfScope() {
- int closed = chrome_frame_test::CloseAllIEWindows();
- DLOG_IF(ERROR, closed != 0)
- << StringPrintf("Closed %i windows forcefully", closed);
- }
-};
-
-// Specialization of CComObjectStackEx that performs object cleanup via
-// calling Base::Uninitialize() before we get to CComObjectStackEx' destructor.
-// The CComObjectStackEx destructor expects the reference count to be 0
-// or it will throw an assert. To work around that and to avoid having to
-// explicitly call Uninitialize() at the end of every test, we override the
-// destructor here to perform the cleanup.
-template <class Base>
-class ComStackObjectWithUninitialize : public CComObjectStackEx<Base> {
- public:
- virtual ~ComStackObjectWithUninitialize() {
- Base::Uninitialize();
- }
-};
-
namespace chrome_frame_test {
ExpectationSet MockWebBrowserEventSink::ExpectNavigationCardinality(
@@ -182,10 +149,6 @@ ExpectationSet MockWebBrowserEventSink::ExpectNewWindow(
} // namespace chrome_frame_test
-ACTION_P(CloseBrowserMock, mock) {
- mock->CloseWebBrowser();
-}
-
ACTION_P3(DelayCloseBrowserMock, loop, delay, mock) {
loop->PostDelayedTask(FROM_HERE, NewRunnableMethod(mock,
&MockWebBrowserEventSink::CloseWebBrowser), delay);
@@ -269,26 +232,10 @@ ACTION_P3(TypeUrlInAddressBar, loop, url, delay) {
next_delay);
}
-void ExpectAddressBarUrl(IWebBrowser2* web_browser2,
- const std::wstring& expected_url) {
- EXPECT_NE(static_cast<IWebBrowser2*>(NULL), web_browser2);
- if (web_browser2) {
- ScopedBstr address_bar_url;
- EXPECT_EQ(S_OK, web_browser2->get_LocationURL(address_bar_url.Receive()));
- EXPECT_EQ(expected_url, std::wstring(address_bar_url));
- }
-}
-
-// To be tacked on to the EXPECT_CALL of OnLoad. This verifies that
-// the address bar URL matches with the URL reported by OnLoad
-ACTION_P(VerifyAddressBarUrl, mock) {
- ExpectAddressBarUrl(mock->web_browser2(), std::wstring(arg0));
-}
-
ACTION_P(VerifyAddressBarUrlWithGcf, mock) {
std::wstring expected_url = L"gcf:";
expected_url += arg0;
- ExpectAddressBarUrl(mock->web_browser2(), expected_url);
+ mock->ExpectAddressBarUrl(expected_url);
}
TEST(ChromeFrameTest, FullTabModeIE_DisallowedUrls) {
@@ -366,7 +313,7 @@ TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_FocusTest) {
EXPECT_CALL(mock, OnLoad(testing::StrCaseEq(kAboutVersion)))
.WillOnce(testing::DoAll(
testing::InvokeWithoutArgs(CreateFunctor(&mock,
- &MockWebBrowserEventSink::ExpectRendererWindowHasfocus)),
+ &MockWebBrowserEventSink::ExpectRendererWindowHasFocus)),
VerifyAddressBarUrlWithGcf(&mock),
CloseBrowserMock(&mock)));
diff --git a/chrome_frame/test/test_mock_with_web_server.h b/chrome_frame/test/test_mock_with_web_server.h
index c14a03f..53fccb1 100644
--- a/chrome_frame/test/test_mock_with_web_server.h
+++ b/chrome_frame/test/test_mock_with_web_server.h
@@ -86,6 +86,14 @@ class MockWebBrowserEventSink : public chrome_frame_test::WebBrowserEventSink {
const std::wstring& url);
};
+ACTION_P(CloseBrowserMock, mock) {
+ mock->CloseWebBrowser();
+}
+
+ACTION_P(VerifyAddressBarUrl, mock) {
+ mock->ExpectAddressBarUrl(std::wstring(arg0));
+}
+
} // namespace chrome_frame_test
#endif // CHROME_FRAME_TEST_MOCK_WITH_WEB_SERVER_H_
diff --git a/chrome_frame/test/test_with_web_server.cc b/chrome_frame/test/test_with_web_server.cc
index 815ad86..2c95f13 100644
--- a/chrome_frame/test/test_with_web_server.cc
+++ b/chrome_frame/test/test_with_web_server.cc
@@ -11,11 +11,11 @@
#include "chrome_frame/utils.h"
#include "chrome_frame/test/chrome_frame_test_utils.h"
+using chrome_frame_test::kChromeFrameLongNavigationTimeoutInSeconds;
+
const wchar_t kDocRoot[] = L"chrome_frame\\test\\data";
const int kLongWaitTimeout = 60 * 1000;
const int kShortWaitTimeout = 25 * 1000;
-const int kChromeFrameLaunchDelay = 5;
-const int kChromeFrameLongNavigationTimeoutInSeconds = 10;
class ChromeFrameTestEnvironment: public testing::Environment {
public: