summaryrefslogtreecommitdiffstats
path: root/chrome_frame/test/chrome_frame_unittests.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome_frame/test/chrome_frame_unittests.cc')
-rw-r--r--chrome_frame/test/chrome_frame_unittests.cc1510
1 files changed, 1510 insertions, 0 deletions
diff --git a/chrome_frame/test/chrome_frame_unittests.cc b/chrome_frame/test/chrome_frame_unittests.cc
new file mode 100644
index 0000000..20826b1
--- /dev/null
+++ b/chrome_frame/test/chrome_frame_unittests.cc
@@ -0,0 +1,1510 @@
+// Copyright (c) 2006-2008 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 <windows.h>
+#include <stdarg.h>
+
+// IShellWindows includes. Unfortunately we can't keep these in
+// alphabetic order since exdisp will bark if some interfaces aren't fully
+// defined.
+#include <mshtml.h>
+#include <exdisp.h>
+
+#include "base/basictypes.h"
+#include "base/file_version_info.h"
+#include "base/file_util.h"
+#include "base/scoped_bstr_win.h"
+#include "base/scoped_comptr_win.h"
+#include "base/scoped_variant_win.h"
+#include "base/sys_info.h"
+#include "gmock/gmock.h"
+#include "net/url_request/url_request_unittest.h"
+#include "chrome_frame/test/chrome_frame_unittests.h"
+#include "chrome_frame/chrome_frame_automation.h"
+#include "chrome_frame/chrome_frame_delegate.h"
+#include "chrome_frame/test/chrome_frame_test_utils.h"
+#include "chrome_frame/test/helper_gmock.h"
+#include "chrome_frame/test_utils.h"
+#include "chrome_frame/utils.h"
+#include "chrome_frame/vectored_handler-impl.h"
+#include "chrome/installer/util/install_util.h"
+#include "chrome/installer/util/helper.h"
+
+const wchar_t kDocRoot[] = L"chrome_frame\\test\\data";
+const int kLongWaitTimeout = 60 * 1000;
+const int kShortWaitTimeout = 25 * 1000;
+
+_ATL_FUNC_INFO WebBrowserEventSink::kNavigateErrorInfo = {
+ CC_STDCALL, VT_EMPTY, 5, {
+ VT_DISPATCH,
+ VT_VARIANT | VT_BYREF,
+ VT_VARIANT | VT_BYREF,
+ VT_VARIANT | VT_BYREF,
+ VT_BOOL | VT_BYREF,
+ }
+};
+
+_ATL_FUNC_INFO WebBrowserEventSink::kNavigateComplete2Info = {
+ CC_STDCALL, VT_EMPTY, 2, {
+ VT_DISPATCH,
+ VT_VARIANT | VT_BYREF
+ }
+};
+
+_ATL_FUNC_INFO WebBrowserEventSink::kBeforeNavigate2Info = {
+ CC_STDCALL, VT_EMPTY, 7, {
+ VT_DISPATCH,
+ VT_VARIANT | VT_BYREF,
+ VT_VARIANT | VT_BYREF,
+ VT_VARIANT | VT_BYREF,
+ VT_VARIANT | VT_BYREF,
+ VT_VARIANT | VT_BYREF,
+ VT_BOOL | VT_BYREF
+ }
+};
+
+
+
+void ChromeFrameTestWithWebServer::SetUp() {
+ server_.SetUp();
+ results_dir_ = server_.GetDataDir();
+ file_util::AppendToPath(&results_dir_, L"dump");
+}
+
+void ChromeFrameTestWithWebServer::TearDown() {
+ CloseBrowser();
+
+ // Web browsers tend to relaunch themselves in other processes, meaning the
+ // KillProcess stuff above might not have actually cleaned up all our browser
+ // instances, so make really sure browsers are dead.
+ base::KillProcesses(chrome_frame_test::kIEImageName, 0, NULL);
+ base::KillProcesses(chrome_frame_test::kIEBrokerImageName, 0, NULL);
+ base::KillProcesses(chrome_frame_test::kFirefoxImageName, 0, NULL);
+ base::KillProcesses(chrome_frame_test::kSafariImageName, 0, NULL);
+ base::KillProcesses(chrome_frame_test::kChromeImageName, 0, NULL);
+
+ server_.TearDown();
+}
+
+bool ChromeFrameTestWithWebServer::LaunchBrowser(BrowserKind browser,
+ const wchar_t* page) {
+ std::wstring url = UTF8ToWide(server_.Resolve(page).spec());
+ browser_ = browser;
+ if (browser == IE) {
+ browser_handle_.Set(chrome_frame_test::LaunchIE(url));
+ } else if (browser == FIREFOX) {
+ browser_handle_.Set(chrome_frame_test::LaunchFirefox(url));
+ } else if (browser == OPERA) {
+ browser_handle_.Set(chrome_frame_test::LaunchOpera(url));
+ } else if (browser == SAFARI) {
+ browser_handle_.Set(chrome_frame_test::LaunchSafari(url));
+ } else if (browser == CHROME) {
+ browser_handle_.Set(chrome_frame_test::LaunchChrome(url));
+ } else {
+ NOTREACHED();
+ }
+
+ return browser_handle_.IsValid();
+}
+
+void ChromeFrameTestWithWebServer::CloseBrowser() {
+ if (!browser_handle_.IsValid())
+ return;
+
+ int attempts = 0;
+ if (browser_ == IE) {
+ attempts = chrome_frame_test::CloseAllIEWindows();
+ } else {
+ attempts = chrome_frame_test::CloseVisibleWindowsOnAllThreads(
+ browser_handle_);
+ }
+
+ if (attempts > 0) {
+ DWORD wait = ::WaitForSingleObject(browser_handle_, 20000);
+ if (wait == WAIT_OBJECT_0) {
+ browser_handle_.Close();
+ } else {
+ DLOG(ERROR) << "WaitForSingleObject returned " << wait;
+ }
+ } else {
+ DLOG(ERROR) << "No attempts to close browser windows";
+ }
+
+ if (browser_handle_.IsValid()) {
+ DWORD exit_code = 0;
+ if (!::GetExitCodeProcess(browser_handle_, &exit_code) ||
+ exit_code == STILL_ACTIVE) {
+ DLOG(ERROR) << L"Forcefully killing browser process. Exit:" << exit_code;
+ base::KillProcess(browser_handle_, 0, true);
+ }
+ browser_handle_.Close();
+ }
+}
+
+bool ChromeFrameTestWithWebServer::BringBrowserToTop() {
+ return chrome_frame_test::EnsureProcessInForeground(GetProcessId(
+ browser_handle_));
+}
+
+bool ChromeFrameTestWithWebServer::WaitForTestToComplete(int milliseconds) {
+ return server_.WaitToFinish(milliseconds);
+}
+
+bool ChromeFrameTestWithWebServer::WaitForOnLoad(int milliseconds) {
+ DWORD start = ::GetTickCount();
+ std::string data;
+ while (!ReadResultFile(L"OnLoadEvent", &data) || data.length() == 0) {
+ DWORD now = ::GetTickCount();
+ if (start > now) {
+ // Very simple check for overflow. In that case we just restart the
+ // wait.
+ start = now;
+ } else if (static_cast<int>(now - start) > milliseconds) {
+ break;
+ }
+ Sleep(100);
+ }
+
+ return data.compare("loaded") == 0;
+}
+
+bool ChromeFrameTestWithWebServer::ReadResultFile(const std::wstring& file_name,
+ std::string* data) {
+ std::wstring full_path = results_dir_;
+ file_util::AppendToPath(&full_path, file_name);
+ return file_util::ReadFileToString(full_path, data);
+}
+
+bool ChromeFrameTestWithWebServer::CheckResultFile(
+ const std::wstring& file_name, const std::string& expected_result) {
+ std::string data;
+ bool ret = ReadResultFile(file_name, &data);
+ if (ret)
+ ret = (data == expected_result);
+
+ if (!ret) {
+ DLOG(ERROR) << "Error text: " << (data.empty() ? "<empty>" : data.c_str());
+ }
+
+ return ret;
+}
+
+void ChromeFrameTestWithWebServer::SimpleBrowserTest(BrowserKind browser,
+ const wchar_t* page, const wchar_t* result_file_to_check) {
+ EXPECT_TRUE(LaunchBrowser(browser, page));
+ ASSERT_TRUE(WaitForTestToComplete(kLongWaitTimeout));
+ ASSERT_TRUE(CheckResultFile(result_file_to_check, "OK"));
+}
+
+void ChromeFrameTestWithWebServer::OptionalBrowserTest(BrowserKind browser,
+ const wchar_t* page, const wchar_t* result_file_to_check) {
+ if (!LaunchBrowser(browser, page)) {
+ DLOG(ERROR) << "Failed to launch browser " << ToString(browser);
+ } else {
+ ASSERT_TRUE(WaitForTestToComplete(kLongWaitTimeout));
+ ASSERT_TRUE(CheckResultFile(result_file_to_check, "OK"));
+ }
+}
+
+void ChromeFrameTestWithWebServer::VersionTest(BrowserKind browser,
+ const wchar_t* page, const wchar_t* result_file_to_check) {
+ std::wstring plugin_path;
+ PathService::Get(base::DIR_MODULE, &plugin_path);
+ file_util::AppendToPath(&plugin_path, L"servers/npchrome_tab.dll");
+
+ static FileVersionInfo* version_info =
+ FileVersionInfo::CreateFileVersionInfo(plugin_path);
+
+ std::wstring version;
+ if (version_info)
+ version = version_info->product_version();
+
+ // If we can't find the npchrome_tab.dll in the src tree, we turn to
+ // the directory where chrome is installed.
+ if (!version_info) {
+ installer::Version* ver_system = InstallUtil::GetChromeVersion(true);
+ installer::Version* ver_user = InstallUtil::GetChromeVersion(false);
+ ASSERT_TRUE(ver_system || ver_user);
+
+ bool system_install = ver_system ? true : false;
+ std::wstring npchrome_path(installer::GetChromeInstallPath(system_install));
+ file_util::AppendToPath(&npchrome_path,
+ ver_system ? ver_system->GetString() : ver_user->GetString());
+ file_util::AppendToPath(&npchrome_path, L"npchrome_tab.dll");
+ version_info = FileVersionInfo::CreateFileVersionInfo(npchrome_path);
+ if (version_info)
+ version = version_info->product_version();
+ }
+
+ EXPECT_TRUE(version_info);
+ EXPECT_FALSE(version.empty());
+ EXPECT_TRUE(LaunchBrowser(browser, page));
+ ASSERT_TRUE(WaitForTestToComplete(kLongWaitTimeout));
+ ASSERT_TRUE(CheckResultFile(result_file_to_check, WideToUTF8(version)));
+}
+
+const wchar_t kPostMessageBasicPage[] = L"files/postmessage_basic_host.html";
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_PostMessageBasic) {
+ SimpleBrowserTest(IE, kPostMessageBasicPage, L"PostMessage");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_PostMessageBasic) {
+ SimpleBrowserTest(FIREFOX, kPostMessageBasicPage, L"PostMessage");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeOpera_PostMessageBasic) {
+ OptionalBrowserTest(OPERA, kPostMessageBasicPage, L"PostMessage");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, FullTabIE_MIMEFilterBasic) {
+ const wchar_t kMIMEFilterBasicPage[] =
+ L"files/chrome_frame_mime_filter_test.html";
+
+ SimpleBrowserTest(IE, kMIMEFilterBasicPage, L"MIMEFilter");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_Resize) {
+ SimpleBrowserTest(IE, L"files/chrome_frame_resize.html", L"Resize");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_Resize) {
+ SimpleBrowserTest(FIREFOX, L"files/chrome_frame_resize.html", L"Resize");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeOpera_Resize) {
+ OptionalBrowserTest(OPERA, L"files/chrome_frame_resize.html", L"Resize");
+}
+
+const wchar_t kNavigateURLAbsolutePage[] =
+ L"files/navigateurl_absolute_host.html";
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_NavigateURLAbsolute) {
+ SimpleBrowserTest(IE, kNavigateURLAbsolutePage, L"NavigateURL");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_NavigateURLAbsolute) {
+ SimpleBrowserTest(FIREFOX, kNavigateURLAbsolutePage, L"NavigateURL");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeOpera_NavigateURLAbsolute) {
+ OptionalBrowserTest(OPERA, kNavigateURLAbsolutePage, L"NavigateURL");
+}
+
+const wchar_t kNavigateURLRelativePage[] =
+ L"files/navigateurl_relative_host.html";
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_NavigateURLRelative) {
+ SimpleBrowserTest(IE, kNavigateURLRelativePage, L"NavigateURL");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_NavigateURLRelative) {
+ SimpleBrowserTest(FIREFOX, kNavigateURLRelativePage, L"NavigateURL");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeOpera_NavigateURLRelative) {
+ OptionalBrowserTest(OPERA, kNavigateURLRelativePage, L"NavigateURL");
+}
+
+const wchar_t kNavigateSimpleObjectFocus[] = L"files/simple_object_focus.html";
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_ObjectFocus) {
+ SimpleBrowserTest(FIREFOX, kNavigateSimpleObjectFocus, L"ObjectFocus");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_ObjectFocus) {
+ SimpleBrowserTest(IE, kNavigateSimpleObjectFocus, L"ObjectFocus");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeOpera_ObjectFocus) {
+ if (!LaunchBrowser(OPERA, kNavigateSimpleObjectFocus)) {
+ DLOG(ERROR) << "Failed to launch browser " << ToString(OPERA);
+ } else {
+ ASSERT_TRUE(WaitForOnLoad(kLongWaitTimeout));
+ BringBrowserToTop();
+ // Tab through a couple of times. Once should be enough in theory
+ // but in practice activating the browser can take a few milliseconds more.
+ bool ok;
+ for (int i = 0;
+ i < 5 && (ok = CheckResultFile(L"ObjectFocus", "OK")) == false;
+ ++i) {
+ Sleep(300);
+ chrome_frame_test::SendMnemonic(VK_TAB, false, false, false);
+ }
+ ASSERT_TRUE(ok);
+ }
+}
+
+const wchar_t kiframeBasicPage[] = L"files/iframe_basic_host.html";
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_iframeBasic) {
+ SimpleBrowserTest(IE, kiframeBasicPage, L"PostMessage");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_iframeBasic) {
+ SimpleBrowserTest(FIREFOX, kiframeBasicPage, L"PostMessage");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeOpera_iframeBasic) {
+ OptionalBrowserTest(OPERA, kiframeBasicPage, L"PostMessage");
+}
+
+const wchar_t kSrcPropertyTestPage[] = L"files/src_property_host.html";
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_SrcProperty) {
+ SimpleBrowserTest(IE, kSrcPropertyTestPage, L"SrcProperty");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_SrcProperty) {
+ SimpleBrowserTest(FIREFOX, kSrcPropertyTestPage, L"SrcProperty");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeOpera_SrcProperty) {
+ OptionalBrowserTest(OPERA, kSrcPropertyTestPage, L"SrcProperty");
+}
+
+const wchar_t kCFInstanceBasicTestPage[] = L"files/CFInstance_basic_host.html";
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_CFInstanceBasic) {
+ SimpleBrowserTest(IE, kCFInstanceBasicTestPage, L"CFInstanceBasic");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_CFInstanceBasic) {
+ SimpleBrowserTest(FIREFOX, kCFInstanceBasicTestPage, L"CFInstanceBasic");
+}
+
+const wchar_t kCFISingletonPage[] = L"files/CFInstance_singleton_host.html";
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_CFInstanceSingleton) {
+ SimpleBrowserTest(IE, kCFISingletonPage, L"CFInstanceSingleton");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_CFInstanceSingleton) {
+ SimpleBrowserTest(FIREFOX, kCFISingletonPage, L"CFInstanceSingleton");
+}
+
+const wchar_t kCFIDelayPage[] = L"files/CFInstance_delay_host.html";
+
+TEST_F(ChromeFrameTestWithWebServer, DISABLED_WidgetModeIE_CFInstanceDelay) {
+ SimpleBrowserTest(IE, kCFIDelayPage, L"CFInstanceDelay");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, DISABLED_WidgetModeFF_CFInstanceDelay) {
+ SimpleBrowserTest(FIREFOX, kCFIDelayPage, L"CFInstanceDelay");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, DISABLED_WidgetModeOpera_CFInstanceDelay) {
+ OptionalBrowserTest(OPERA, kCFIDelayPage, L"CFInstanceDelay");
+}
+
+const wchar_t kCFIFallbackPage[] = L"files/CFInstance_fallback_host.html";
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_CFInstanceFallback) {
+ SimpleBrowserTest(IE, kCFIFallbackPage, L"CFInstanceFallback");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_CFInstanceFallback) {
+ SimpleBrowserTest(FIREFOX, kCFIFallbackPage, L"CFInstanceFallback");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeOpera_CFInstanceFallback) {
+ OptionalBrowserTest(OPERA, kCFIFallbackPage, L"CFInstanceFallback");
+}
+
+const wchar_t kCFINoSrcPage[] = L"files/CFInstance_no_src_host.html";
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_CFInstanceNoSrc) {
+ SimpleBrowserTest(IE, kCFINoSrcPage, L"CFInstanceNoSrc");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_CFInstanceNoSrc) {
+ SimpleBrowserTest(FIREFOX, kCFINoSrcPage, L"CFInstanceNoSrc");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeOpera_CFInstanceNoSrc) {
+ OptionalBrowserTest(OPERA, kCFINoSrcPage, L"CFInstanceNoSrc");
+}
+
+const wchar_t kCFIIfrOnLoadPage[] = L"files/CFInstance_iframe_onload_host.html";
+
+// disabled since it's unlikely that we care about this case
+TEST_F(ChromeFrameTestWithWebServer, DISABLED_WidgetModeIE_CFInstanceIfrOnLoad) {
+ SimpleBrowserTest(IE, kCFIIfrOnLoadPage, L"CFInstanceIfrOnLoad");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_CFInstanceIfrOnLoad) {
+ SimpleBrowserTest(FIREFOX, kCFIIfrOnLoadPage, L"CFInstanceIfrOnLoad");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeOpera_CFInstanceIfrOnLoad) {
+ OptionalBrowserTest(OPERA, kCFIIfrOnLoadPage, L"CFInstanceIfrOnLoad");
+}
+
+const wchar_t kCFIZeroSizePage[] = L"files/CFInstance_zero_size_host.html";
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_CFInstanceZeroSize) {
+ SimpleBrowserTest(IE, kCFIZeroSizePage, L"CFInstanceZeroSize");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_CFInstanceZeroSize) {
+ SimpleBrowserTest(FIREFOX, kCFIZeroSizePage, L"CFInstanceZeroSize");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeOpera_CFInstanceZeroSize) {
+ OptionalBrowserTest(OPERA, kCFIZeroSizePage, L"CFInstanceZeroSize");
+}
+
+const wchar_t kCFIIfrPostPage[] = L"files/CFInstance_iframe_post_host.html";
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_CFInstanceIfrPost) {
+ SimpleBrowserTest(IE, kCFIIfrPostPage, L"CFInstanceIfrPost");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_CFInstanceIfrPost) {
+ SimpleBrowserTest(FIREFOX, kCFIIfrPostPage, L"CFInstanceIfrPost");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeChrome_CFInstanceIfrPost) {
+ OptionalBrowserTest(CHROME, kCFIIfrPostPage, L"CFInstanceIfrPost");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeSafari_CFInstanceIfrPost) {
+ OptionalBrowserTest(SAFARI, kCFIIfrPostPage, L"CFInstanceIfrPost");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeOpera_CFInstanceIfrPost) {
+ OptionalBrowserTest(OPERA, kCFIIfrPostPage, L"CFInstanceIfrPost");
+}
+
+const wchar_t kCFIPostPage[] = L"files/CFInstance_post_host.html";
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_CFInstancePost) {
+ SimpleBrowserTest(IE, kCFIPostPage, L"CFInstancePost");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_CFInstancePost) {
+ SimpleBrowserTest(FIREFOX, kCFIPostPage, L"CFInstancePost");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeChrome_CFInstancePost) {
+ OptionalBrowserTest(CHROME, kCFIPostPage, L"CFInstancePost");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeSafari_CFInstancePost) {
+ OptionalBrowserTest(SAFARI, kCFIPostPage, L"CFInstancePost");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, DISABLED_WidgetModeOpera_CFInstancePost) {
+ OptionalBrowserTest(OPERA, kCFIPostPage, L"CFInstancePost");
+}
+
+const wchar_t kCFIRPCPage[] = L"files/CFInstance_rpc_host.html";
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_CFInstanceRPC) {
+ SimpleBrowserTest(IE, kCFIRPCPage, L"CFInstanceRPC");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_CFInstanceRPC) {
+ SimpleBrowserTest(FIREFOX, kCFIRPCPage, L"CFInstanceRPC");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeChrome_CFInstanceRPC) {
+ OptionalBrowserTest(CHROME, kCFIRPCPage, L"CFInstanceRPC");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeSafari_CFInstanceRPC) {
+ OptionalBrowserTest(SAFARI, kCFIRPCPage, L"CFInstanceRPC");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, DISABLED_WidgetModeOpera_CFInstanceRPC) {
+ OptionalBrowserTest(OPERA, kCFIRPCPage, L"CFInstanceRPC");
+}
+
+const wchar_t kCFIRPCInternalPage[] =
+ L"files/CFInstance_rpc_internal_host.html";
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_CFInstanceRPCInternal) {
+ SimpleBrowserTest(IE, kCFIRPCInternalPage, L"CFInstanceRPCInternal");
+}
+
+// Disabled: http://b/issue?id=2050201
+TEST_F(ChromeFrameTestWithWebServer, DISABLED_WidgetModeFF_CFInstanceRPCInternal) {
+ SimpleBrowserTest(FIREFOX, kCFIRPCInternalPage, L"CFInstanceRPCInternal");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeChrome_CFInstanceRPCInternal) {
+ OptionalBrowserTest(CHROME, kCFIRPCInternalPage, L"CFInstanceRPCInternal");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeSafari_CFInstanceRPCInternal) {
+ OptionalBrowserTest(SAFARI, kCFIRPCInternalPage, L"CFInstanceRPCInternal");
+}
+
+const wchar_t kCFIDefaultCtorPage[] =
+ L"files/CFInstance_default_ctor_host.html";
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_CFInstanceDefaultCtor) {
+ SimpleBrowserTest(IE, kCFIDefaultCtorPage, L"CFInstanceDefaultCtor");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_CFInstanceDefaultCtor) {
+ SimpleBrowserTest(FIREFOX, kCFIDefaultCtorPage, L"CFInstanceDefaultCtor");
+}
+
+// Class that mocks external call from VectoredHandlerT for testing purposes.
+class EMock : public VEHTraitsBase {
+ public:
+ static inline bool WriteDump(EXCEPTION_POINTERS* p) {
+ g_dump_made = true;
+ return true;
+ }
+
+ static inline void* Register(PVECTORED_EXCEPTION_HANDLER func,
+ const void* module_start,
+ const void* module_end) {
+ VEHTraitsBase::SetModule(module_start, module_end);
+ // Return some arbitrary number, expecting to get the same on Unregister()
+ return reinterpret_cast<void*>(4);
+ }
+
+ static inline ULONG Unregister(void* handle) {
+ EXPECT_EQ(handle, reinterpret_cast<void*>(4));
+ return 1;
+ }
+
+ static inline WORD RtlCaptureStackBackTrace(DWORD FramesToSkip,
+ DWORD FramesToCapture, void** BackTrace, DWORD* BackTraceHash) {
+ EXPECT_EQ(2, FramesToSkip);
+ EXPECT_LE(FramesToSkip + FramesToCapture,
+ VectoredHandlerBase::max_back_trace);
+ memcpy(BackTrace, g_stack, g_stack_entries * sizeof(BackTrace[0]));
+ return g_stack_entries;
+ }
+
+ static inline EXCEPTION_REGISTRATION_RECORD* RtlpGetExceptionList() {
+ return g_seh_chain;
+ }
+
+ // Test helpers
+
+ // Create fake SEH chain of random filters - with and without our module.
+ static void SetHaveSEHFilter() {
+ SetSEHChain(reinterpret_cast<const char*>(g_module_start) - 0x1000,
+ reinterpret_cast<const char*>(g_module_start) + 0x1000,
+ reinterpret_cast<const char*>(g_module_end) + 0x7127,
+ NULL);
+ }
+
+ static void SetNoSEHFilter() {
+ SetSEHChain(reinterpret_cast<const char*>(g_module_start) - 0x1000,
+ reinterpret_cast<const char*>(g_module_end) + 0x7127,
+ NULL);
+ }
+
+ // Create fake stack - with and without our module.
+ static void SetOnStack() {
+ SetStack(reinterpret_cast<const char*>(g_module_start) - 0x11283,
+ reinterpret_cast<const char*>(g_module_start) - 0x278361,
+ reinterpret_cast<const char*>(g_module_start) + 0x9171,
+ reinterpret_cast<const char*>(g_module_end) + 1231,
+ NULL);
+ }
+
+ static void SetNotOnStack() {
+ SetStack(reinterpret_cast<const char*>(g_module_start) - 0x11283,
+ reinterpret_cast<const char*>(g_module_start) - 0x278361,
+ reinterpret_cast<const char*>(g_module_end) + 1231,
+ NULL);
+ }
+
+ // Populate stack array
+ static void SetStack(const void* p, ...) {
+ va_list vl;
+ va_start(vl, p);
+ g_stack_entries = 0;
+ for (; p; ++g_stack_entries) {
+ CHECK(g_stack_entries < arraysize(g_stack));
+ g_stack[g_stack_entries] = p;
+ p = va_arg(vl, const void*);
+ }
+ }
+
+ static void SetSEHChain(const void* p, ...) {
+ va_list vl;
+ va_start(vl, p);
+ int i = 0;
+ for (; p; ++i) {
+ CHECK(i + 1 < arraysize(g_seh_chain));
+ g_seh_chain[i].Handler = const_cast<void*>(p);
+ g_seh_chain[i].Next = &g_seh_chain[i + 1];
+ p = va_arg(vl, const void*);
+ }
+
+ g_seh_chain[i].Next = EXCEPTION_CHAIN_END;
+ }
+
+ static EXCEPTION_REGISTRATION_RECORD g_seh_chain[25];
+ static const void* g_stack[VectoredHandlerBase::max_back_trace];
+ static WORD g_stack_entries;
+ static bool g_dump_made;
+};
+
+EXCEPTION_REGISTRATION_RECORD EMock::g_seh_chain[25];
+const void* EMock::g_stack[VectoredHandlerBase::max_back_trace];
+WORD EMock::g_stack_entries;
+bool EMock::g_dump_made;
+
+typedef VectoredHandlerT<EMock> VectoredHandlerMock;
+
+class ExPtrsHelper : public _EXCEPTION_POINTERS {
+ public:
+ ExPtrsHelper() {
+ ExceptionRecord = &er_;
+ ContextRecord = &ctx_;
+ ZeroMemory(&er_, sizeof(er_));
+ ZeroMemory(&ctx_, sizeof(ctx_));
+ }
+
+ void Set(DWORD code, void* address, DWORD flags) {
+ er_.ExceptionCode = code;
+ er_.ExceptionAddress = address;
+ er_.ExceptionFlags = flags;
+ }
+
+ EXCEPTION_RECORD er_;
+ CONTEXT ctx_;
+};
+
+
+TEST(ChromeFrame, ExceptionReport) {
+ char* s = reinterpret_cast<char*>(0x30000000);
+ char* e = s + 0x10000;
+ void* handler = VectoredHandlerMock::Register(s, e);
+ char* our_code = s + 0x1111;
+ char* not_our_code = s - 0x5555;
+ char* not_our_code2 = e + 0x5555;
+
+ ExPtrsHelper ex;
+ // Exception in our code, but we have SEH filter
+ ex.Set(STATUS_ACCESS_VIOLATION, our_code, 0);
+ EMock::SetHaveSEHFilter();
+ EMock::SetOnStack();
+ EXPECT_EQ(ExceptionContinueSearch, VectoredHandlerMock::VectoredHandler(&ex));
+ EXPECT_EQ(1, VectoredHandlerMock::g_exceptions_seen);
+ EXPECT_FALSE(EMock::g_dump_made);
+
+ // RPC_E_DISCONNECTED (0x80010108) is "The object invoked has disconnected
+ // from its clients", shall not be caught since it's a warning only.
+ ex.Set(RPC_E_DISCONNECTED, our_code, 0);
+ EMock::SetHaveSEHFilter();
+ EMock::SetOnStack();
+ EXPECT_EQ(ExceptionContinueSearch, VectoredHandlerMock::VectoredHandler(&ex));
+ EXPECT_EQ(1, VectoredHandlerMock::g_exceptions_seen);
+ EXPECT_FALSE(EMock::g_dump_made);
+
+
+ // Exception, not in our code, we do not have SEH and we are not in stack.
+ ex.Set(STATUS_INTEGER_DIVIDE_BY_ZERO, not_our_code, 0);
+ EMock::SetNoSEHFilter();
+ EMock::SetNotOnStack();
+ EXPECT_EQ(ExceptionContinueSearch, VectoredHandlerMock::VectoredHandler(&ex));
+ EXPECT_EQ(2, VectoredHandlerMock::g_exceptions_seen);
+ EXPECT_FALSE(EMock::g_dump_made);
+
+ // Exception, not in our code, no SEH, but we are on the stack.
+ ex.Set(STATUS_INTEGER_DIVIDE_BY_ZERO, not_our_code2, 0);
+ EMock::SetNoSEHFilter();
+ EMock::SetOnStack();
+ EXPECT_EQ(ExceptionContinueSearch, VectoredHandlerMock::VectoredHandler(&ex));
+ EXPECT_EQ(3, VectoredHandlerMock::g_exceptions_seen);
+ EXPECT_TRUE(EMock::g_dump_made);
+ EMock::g_dump_made = false;
+
+
+ // Exception, in our code, no SEH, not on stack (assume FPO screwed us)
+ ex.Set(STATUS_INTEGER_DIVIDE_BY_ZERO, our_code, 0);
+ EMock::SetNoSEHFilter();
+ EMock::SetNotOnStack();
+ EXPECT_EQ(ExceptionContinueSearch, VectoredHandlerMock::VectoredHandler(&ex));
+ EXPECT_EQ(4, VectoredHandlerMock::g_exceptions_seen);
+ EXPECT_TRUE(EMock::g_dump_made);
+ EMock::g_dump_made = false;
+
+ VectoredHandlerMock::Unregister();
+}
+
+const wchar_t kInitializeHiddenPage[] = L"files/initialize_hidden.html";
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_InitializeHidden) {
+ SimpleBrowserTest(IE, kInitializeHiddenPage, L"InitializeHidden");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_InitializeHidden) {
+ SimpleBrowserTest(FIREFOX, kInitializeHiddenPage, L"InitializeHidden");
+}
+
+// Disabled due to a problem with Opera.
+// http://b/issue?id=1708275
+TEST_F(ChromeFrameTestWithWebServer, DISABLED_WidgetModeOpera_InitializeHidden) {
+ OptionalBrowserTest(OPERA, kInitializeHiddenPage, L"InitializeHidden");
+}
+
+const wchar_t kInHeadPage[] = L"files/in_head.html";
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_InHead) {
+ SimpleBrowserTest(FIREFOX, kInHeadPage, L"InHead");
+}
+
+const wchar_t kVersionPage[] = L"files/version.html";
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_Version) {
+ VersionTest(IE, kVersionPage, L"version");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_Version) {
+ VersionTest(FIREFOX, kVersionPage, L"version");
+}
+
+const wchar_t kEventListenerPage[] = L"files/event_listener.html";
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_EventListener) {
+ SimpleBrowserTest(IE, kEventListenerPage, L"EventListener");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_EventListener) {
+ SimpleBrowserTest(FIREFOX, kEventListenerPage, L"EventListener");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeOpera_EventListener) {
+ OptionalBrowserTest(OPERA, kEventListenerPage, L"EventListener");
+}
+
+const wchar_t kPrivilegedApisPage[] = L"files/privileged_apis_host.html";
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeIE_PrivilegedApis) {
+ SimpleBrowserTest(IE, kPrivilegedApisPage, L"PrivilegedApis");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeFF_PrivilegedApis) {
+ SimpleBrowserTest(FIREFOX, kPrivilegedApisPage, L"PrivilegedApis");
+}
+
+TEST_F(ChromeFrameTestWithWebServer, WidgetModeOpera_PrivilegedApis) {
+ OptionalBrowserTest(OPERA, kPrivilegedApisPage, L"PrivilegedApis");
+}
+
+class ChromeFrameTestEnvironment: public testing::Environment {
+ public:
+ ~ChromeFrameTestEnvironment() {
+ }
+
+ void SetUp() {
+ ScopedChromeFrameRegistrar::RegisterDefaults();
+ }
+
+ void TearDown() {
+ }
+};
+
+::testing::Environment* const chrome_frame_env =
+ ::testing::AddGlobalTestEnvironment(new ChromeFrameTestEnvironment);
+
+// TODO(stoyan): - Move everything below in separate file(s).
+struct LaunchDelegateMock : public ProxyFactory::LaunchDelegate {
+ MOCK_METHOD2(LaunchComplete, void(ChromeFrameAutomationProxy*,
+ AutomationLaunchResult));
+};
+
+TEST(ProxyFactoryTest, CreateDestroy) {
+ ProxyFactory f;
+ LaunchDelegateMock d;
+ EXPECT_CALL(d, LaunchComplete(testing::NotNull(), testing::_)).Times(1);
+ void* id = f.GetAutomationServer(0, L"Adam.N.Epilinter", L"", false, &d);
+ f.ReleaseAutomationServer(id);
+}
+
+TEST(ProxyFactoryTest, CreateSameProfile) {
+ ProxyFactory f;
+ LaunchDelegateMock d;
+ EXPECT_CALL(d, LaunchComplete(testing::NotNull(), testing::_)).Times(2);
+ void* i1 = f.GetAutomationServer(0, L"Dr. Gratiano Forbeson", L"", false, &d);
+ void* i2 = f.GetAutomationServer(0, L"Dr. Gratiano Forbeson", L"", false, &d);
+ EXPECT_EQ(i1, i2);
+ f.ReleaseAutomationServer(i2);
+ f.ReleaseAutomationServer(i1);
+}
+
+TEST(ProxyFactoryTest, CreateDifferentProfiles) {
+ ProxyFactory f;
+ LaunchDelegateMock d;
+ EXPECT_CALL(d, LaunchComplete(testing::NotNull(), testing::_)).Times(2);
+ void* i1 = f.GetAutomationServer(0, L"Adam.N.Epilinter", L"", false, &d);
+ void* i2 = f.GetAutomationServer(0, L"Dr. Gratiano Forbeson", L"", false, &d);
+ EXPECT_NE(i1, i2);
+ f.ReleaseAutomationServer(i2);
+ f.ReleaseAutomationServer(i1);
+}
+
+// ChromeFrameAutomationClient [CFAC] tests.
+struct MockCFDelegate : public ChromeFrameDelegateImpl {
+ MOCK_CONST_METHOD0(GetWindow, WindowType());
+ MOCK_METHOD1(GetBounds, void(RECT* bounds));
+ MOCK_METHOD0(GetDocumentUrl, std::string());
+ MOCK_METHOD2(ExecuteScript, bool(const std::string& script,
+ std::string* result));
+ MOCK_METHOD0(OnAutomationServerReady, void());
+ MOCK_METHOD2(OnAutomationServerLaunchFailed, void(
+ AutomationLaunchResult reason, const std::string& server_version));
+ // This remains in interface since we call it if Navigate()
+ // returns immediate error.
+ MOCK_METHOD2(OnLoadFailed, void(int error_code, const std::string& url));
+
+ // Do not mock this method. :) Use it as message demuxer and dispatcher
+ // to the following methods (which we mock)
+ // MOCK_METHOD1(OnMessageReceived, void(const IPC::Message&));
+
+
+ MOCK_METHOD2(OnNavigationStateChanged, void(int tab_handle, int flags));
+ MOCK_METHOD2(OnUpdateTargetUrl, void(int tab_handle,
+ const std::wstring& new_target_url));
+ MOCK_METHOD2(OnAcceleratorPressed, void(int tab_handle,
+ const MSG& accel_message));
+ MOCK_METHOD2(OnTabbedOut, void(int tab_handle, bool reverse));
+ MOCK_METHOD3(OnOpenURL, void(int tab_handle, const GURL& url,
+ int open_disposition));
+ MOCK_METHOD2(OnDidNavigate, void(int tab_handle,
+ const IPC::NavigationInfo& navigation_info));
+ MOCK_METHOD3(OnNavigationFailed, void(int tab_handle, int error_code,
+ const GURL& gurl));
+ MOCK_METHOD2(OnLoad, void(int tab_handle, const GURL& url));
+ MOCK_METHOD4(OnMessageFromChromeFrame, void(int tab_handle,
+ const std::string& message,
+ const std::string& origin,
+ const std::string& target));
+ MOCK_METHOD5(OnHandleContextMenu, void(int tab_handle, HANDLE menu_handle,
+ int x_pos, int y_pos, int align_flags));
+ MOCK_METHOD3(OnRequestStart, void(int tab_handle, int request_id,
+ const IPC::AutomationURLRequest& request));
+ MOCK_METHOD3(OnRequestRead, void(int tab_handle, int request_id,
+ int bytes_to_read));
+ MOCK_METHOD3(OnRequestEnd, void(int tab_handle, int request_id,
+ const URLRequestStatus& status));
+ MOCK_METHOD3(OnSetCookieAsync, void(int tab_handle, const GURL& url,
+ const std::string& cookie));
+
+ // Use for sending network responses
+ void SetAutomationSender(IPC::Message::Sender* automation) {
+ automation_ = automation;
+ }
+
+ // Set-expectation helpers
+ void SetOnNavigationStateChanged(int tab_handle) {
+ EXPECT_CALL(*this,
+ OnNavigationStateChanged(testing::Eq(tab_handle), testing::_))
+ .Times(testing::AnyNumber());
+ }
+
+ // Response sender helpers
+ void ReplyStarted(const IPC::AutomationURLResponse* response,
+ int tab_handle, int request_id,
+ const IPC::AutomationURLRequest& request) {
+ automation_->Send(new AutomationMsg_RequestStarted(0, tab_handle,
+ request_id, *response));
+ }
+
+ void ReplyData(const std::string* data, int tab_handle, int request_id,
+ int bytes_to_read) {
+ automation_->Send(new AutomationMsg_RequestData(0, tab_handle,
+ request_id, *data));
+ }
+
+ void ReplyEOF(int tab_handle, int request_id) {
+ automation_->Send(new AutomationMsg_RequestEnd(0, tab_handle,
+ request_id, URLRequestStatus()));
+ }
+
+ void Reply404(int tab_handle, int request_id,
+ const IPC::AutomationURLRequest& request) {
+ const IPC::AutomationURLResponse notfound = {"", "HTTP/1.1 404\r\n\r\n"};
+ automation_->Send(new AutomationMsg_RequestStarted(0, tab_handle,
+ request_id, notfound));
+ automation_->Send(new AutomationMsg_RequestEnd(0, tab_handle,
+ request_id, URLRequestStatus()));
+ }
+
+ IPC::Message::Sender* automation_;
+};
+
+class MockProxyFactory : public ProxyFactory {
+ public:
+ MOCK_METHOD5(GetAutomationServer, void*(int, const std::wstring&,
+ const std::wstring& extra_argument, bool, ProxyFactory::LaunchDelegate*));
+ MOCK_METHOD1(ReleaseAutomationServer, bool(void* id));
+
+ MockProxyFactory() : thread_("mock factory worker") {
+ thread_.Start();
+ loop_ = thread_.message_loop();
+ }
+
+ // Fake implementation
+ void GetServerImpl(ChromeFrameAutomationProxy* pxy,
+ AutomationLaunchResult result,
+ int timeout,
+ ProxyFactory::LaunchDelegate* d) {
+ Task* task = NewRunnableMethod(d,
+ &ProxyFactory::LaunchDelegate::LaunchComplete, pxy, result);
+ loop_->PostDelayedTask(FROM_HERE, task, timeout/2);
+ }
+
+ base::Thread thread_;
+ MessageLoop* loop_;
+};
+
+class MockAutomationProxy : public ChromeFrameAutomationProxy {
+ public:
+ MOCK_METHOD1(Send, bool(IPC::Message*));
+ MOCK_METHOD3(SendAsAsync, void(IPC::SyncMessage* msg, void* callback,
+ void* key));
+ MOCK_METHOD1(CancelAsync, void(void* key));
+ MOCK_METHOD1(CreateTabProxy, scoped_refptr<TabProxy>(int handle));
+ MOCK_METHOD0(server_version, std::string(void));
+ MOCK_METHOD1(SendProxyConfig, void(const std::string&));
+ MOCK_METHOD1(SetEnableExtensionAutomation, void(bool enable));
+
+ ~MockAutomationProxy() {}
+};
+
+struct MockAutomationMessageSender : public AutomationMessageSender {
+ MOCK_METHOD1(Send, bool(IPC::Message*));
+ MOCK_METHOD3(SendWithTimeout, bool(IPC::Message* , int , bool*));
+
+ void ForwardTo(MockAutomationProxy *p) {
+ proxy_ = p;
+ ON_CALL(*this, Send(testing::_))
+ .WillByDefault(testing::Invoke(proxy_, &MockAutomationProxy::Send));
+ }
+
+ MockAutomationProxy* proxy_;
+};
+
+template <> struct RunnableMethodTraits<ProxyFactory::LaunchDelegate> {
+ static void RetainCallee(ProxyFactory::LaunchDelegate* obj) {}
+ static void ReleaseCallee(ProxyFactory::LaunchDelegate* obj) {}
+};
+
+template <> struct RunnableMethodTraits<MockProxyFactory> {
+ static void RetainCallee(MockProxyFactory* obj) {}
+ static void ReleaseCallee(MockProxyFactory* obj) {}
+};
+
+template <> struct RunnableMethodTraits<ChromeFrameAutomationClient> {
+ static void RetainCallee(ChromeFrameAutomationClient* obj) {}
+ static void ReleaseCallee(ChromeFrameAutomationClient* obj) {}
+};
+
+// MessageLoopForUI wrapper that runs only for a limited time.
+// We need a UI message loop in the main thread.
+struct TimedMsgLoop {
+ public:
+ void RunFor(int seconds) {
+ loop_.PostDelayedTask(FROM_HERE, new MessageLoop::QuitTask, 1000 * seconds);
+ loop_.MessageLoop::Run();
+ }
+
+ void Quit() {
+ loop_.PostTask(FROM_HERE, new MessageLoop::QuitTask);
+ }
+
+ MessageLoopForUI loop_;
+};
+
+template <> struct RunnableMethodTraits<TimedMsgLoop> {
+ static void RetainCallee(TimedMsgLoop* obj) {}
+ static void ReleaseCallee(TimedMsgLoop* obj) {}
+};
+
+// Saves typing. It's somewhat hard to create a wrapper around
+// testing::InvokeWithoutArgs since it returns a
+// non-public (testing::internal) type.
+#define QUIT_LOOP(loop) testing::InvokeWithoutArgs(TaskHolder(\
+ NewRunnableMethod(&loop, &TimedMsgLoop::Quit)))
+
+// We mock ChromeFrameDelegate only. The rest is with real AutomationProxy
+TEST(CFACWithChrome, CreateTooFast) {
+ MockCFDelegate cfd;
+ TimedMsgLoop loop;
+ int timeout = 0; // Chrome cannot send Hello message so fast.
+ const std::wstring profile = L"Adam.N.Epilinter";
+
+ scoped_ptr<ChromeFrameAutomationClient> client;
+ client.reset(new ChromeFrameAutomationClient());
+
+ EXPECT_CALL(cfd, OnAutomationServerLaunchFailed(AUTOMATION_TIMEOUT,
+ testing::_))
+ .Times(1)
+ .WillOnce(QUIT_LOOP(loop));
+
+ EXPECT_TRUE(client->Initialize(&cfd, timeout, false, profile, L"", false));
+ loop.RunFor(10);
+ client->Uninitialize();
+}
+
+// This test may fail if Chrome take more that 10 seconds (timeout var) to
+// launch. In this case GMock shall print something like "unexpected call to
+// OnAutomationServerLaunchFailed". I'm yet to find out how to specify
+// that this is an unexpected call, and still to execute and action.
+TEST(CFACWithChrome, CreateNotSoFast) {
+ MockCFDelegate cfd;
+ TimedMsgLoop loop;
+ const std::wstring profile = L"Adam.N.Epilinter";
+ int timeout = 10000;
+
+ scoped_ptr<ChromeFrameAutomationClient> client;
+ client.reset(new ChromeFrameAutomationClient);
+
+ EXPECT_CALL(cfd, OnAutomationServerReady())
+ .Times(1)
+ .WillOnce(QUIT_LOOP(loop));
+
+ EXPECT_CALL(cfd, OnAutomationServerLaunchFailed(testing::_, testing::_))
+ .Times(0);
+
+ EXPECT_TRUE(client->Initialize(&cfd, timeout, false, profile, L"", false));
+
+ loop.RunFor(11);
+ client->Uninitialize();
+ client.reset(NULL);
+}
+
+MATCHER_P(MsgType, msg_type, "IPC::Message::type()") {
+ const IPC::Message& m = arg;
+ return (m.type() == msg_type);
+}
+
+MATCHER_P(EqNavigationInfoUrl, url, "IPC::NavigationInfo matcher") {
+ if (url.is_valid() && url != arg.url)
+ return false;
+ // TODO: other members
+ return true;
+}
+
+TEST(CFACWithChrome, NavigateOk) {
+ MockCFDelegate cfd;
+ TimedMsgLoop loop;
+ const std::wstring profile = L"Adam.N.Epilinter";
+ const std::string url = "about:version";
+ int timeout = 10000;
+
+ scoped_ptr<ChromeFrameAutomationClient> client;
+ client.reset(new ChromeFrameAutomationClient);
+
+ EXPECT_CALL(cfd, OnAutomationServerReady())
+ .WillOnce(testing::InvokeWithoutArgs(TaskHolder(NewRunnableMethod(
+ client.get(), &ChromeFrameAutomationClient::InitiateNavigation,
+ url))));
+
+// cfd.SetOnNavigationStateChanged();
+ EXPECT_CALL(cfd,
+ OnNavigationStateChanged(testing::_, testing::_))
+ .Times(testing::AnyNumber());
+
+ {
+ testing::InSequence s;
+
+ EXPECT_CALL(cfd, OnDidNavigate(testing::_, EqNavigationInfoUrl(GURL())))
+ .Times(1);
+
+ EXPECT_CALL(cfd, OnUpdateTargetUrl(testing::_, testing::_)).Times(1);
+
+ EXPECT_CALL(cfd, OnLoad(testing::_, testing::_))
+ .Times(1)
+ .WillOnce(QUIT_LOOP(loop));
+ }
+
+ EXPECT_TRUE(client->Initialize(&cfd, timeout, false, profile, L"", false));
+ loop.RunFor(10);
+ client->Uninitialize();
+ client.reset(NULL);
+}
+
+// Bug: http://b/issue?id=2033644
+TEST(CFACWithChrome, DISABLED_NavigateFailed) {
+ MockCFDelegate cfd;
+ TimedMsgLoop loop;
+ const std::wstring profile = L"Adam.N.Epilinter";
+ const std::string url = "http://127.0.0.3:65412/";
+ int timeout = 10000;
+
+ scoped_ptr<ChromeFrameAutomationClient> client;
+ client.reset(new ChromeFrameAutomationClient);
+
+ EXPECT_CALL(cfd, OnAutomationServerReady())
+ .WillOnce(testing::InvokeWithoutArgs(TaskHolder(NewRunnableMethod(
+ client.get(), &ChromeFrameAutomationClient::InitiateNavigation,
+ url))));
+
+ EXPECT_CALL(cfd,
+ OnNavigationStateChanged(testing::_, testing::_))
+ .Times(testing::AnyNumber());
+
+ EXPECT_CALL(cfd, OnNavigationFailed(testing::_, testing::_, testing::_))
+ .Times(1);
+
+ EXPECT_CALL(cfd, OnUpdateTargetUrl(testing::_, testing::_))
+ .Times(testing::AnyNumber());
+
+ EXPECT_CALL(cfd, OnLoad(testing::_, testing::_))
+ .Times(0);
+
+ EXPECT_TRUE(client->Initialize(&cfd, timeout, false, profile, L"", false));
+
+ loop.RunFor(10);
+ client->Uninitialize();
+ client.reset(NULL);
+}
+
+MATCHER_P(EqURLRequest, x, "IPC::AutomationURLRequest matcher") {
+ if (arg.url != x.url)
+ return false;
+ if (arg.method != x.method)
+ return false;
+ if (arg.referrer != x.referrer)
+ return false;
+ if (arg.extra_request_headers != x.extra_request_headers)
+ return false;
+ // TODO: uploaddata member
+ return true;
+}
+
+MATCHER_P(EqUrlGet, url, "Quick URL matcher for 'HTTP GET' request") {
+ if (arg.url != url)
+ return false;
+ if (arg.method != "GET")
+ return false;
+ return true;
+}
+
+TEST(CFACWithChrome, UseHostNetworkStack) {
+ MockCFDelegate cfd;
+ TimedMsgLoop loop;
+ const std::wstring profile = L"Adam.N.Epilinter";
+ const std::string url = "http://bongo.com";
+ int timeout = 10000;
+
+ scoped_ptr<ChromeFrameAutomationClient> client;
+ client.reset(new ChromeFrameAutomationClient);
+ client->set_use_chrome_network(false);
+ cfd.SetAutomationSender(client.get());
+
+ EXPECT_CALL(cfd, OnAutomationServerReady())
+ .WillOnce(testing::InvokeWithoutArgs(TaskHolder(NewRunnableMethod(
+ client.get(), &ChromeFrameAutomationClient::InitiateNavigation,
+ url))));
+
+ EXPECT_CALL(cfd, OnNavigationStateChanged(testing::_, testing::_))
+ .Times(testing::AnyNumber());
+
+ EXPECT_CALL(cfd, GetBounds(testing::_))
+ .Times(testing::AtMost(1));
+
+ EXPECT_CALL(cfd, OnUpdateTargetUrl(testing::_, testing::_))
+ .Times(testing::AnyNumber());
+
+ // Note slash appending to the url string, because of GURL inside chrome
+ const IPC::AutomationURLResponse found = {"", "HTTP/0.9 200\r\n\r\n\r\n", };
+
+ // Hard coded tab and request ids
+ static const int tab_id = 1;
+ int request_id = 2;
+
+ EXPECT_CALL(cfd, OnRequestStart(tab_id, request_id, EqUrlGet(url + '/')))
+ .Times(1)
+ .WillOnce(testing::Invoke(CBF(&cfd, &MockCFDelegate::ReplyStarted,
+ &found)));
+
+ // Return some trivial page, that have a link to a "logo.gif" image
+ const std::string data = "<!DOCTYPE html><title>Hello</title>"
+ "<img src=\"logo.gif\">";
+ EXPECT_CALL(cfd, OnRequestRead(tab_id, request_id, testing::Ge(0)))
+ .Times(2)
+ .WillOnce(testing::Invoke(CBF(&cfd, &MockCFDelegate::ReplyData, &data)))
+ .WillOnce(testing::WithArgs<0, 1>(testing::Invoke(CBF(&cfd,
+ &MockCFDelegate::ReplyEOF))));
+
+ EXPECT_CALL(cfd, OnDidNavigate(tab_id, EqNavigationInfoUrl(GURL(url))))
+ .Times(1);
+ EXPECT_CALL(cfd, OnLoad(tab_id, GURL(url)))
+ .Times(1);
+
+ // Expect request for logo.gif
+ request_id++;
+ EXPECT_CALL(cfd,
+ OnRequestStart(tab_id, request_id, EqUrlGet(url + "/logo.gif")))
+ .Times(1)
+ .WillOnce(testing::Invoke(CBF(&cfd, &MockCFDelegate::Reply404)));
+
+ EXPECT_CALL(cfd, OnRequestRead(tab_id, request_id, testing::_))
+ .Times(testing::AtMost(1));
+
+ // Chrome makes a brave request for favicon.ico
+ request_id++;
+ EXPECT_CALL(cfd,
+ OnRequestStart(tab_id, request_id, EqUrlGet(url + "/favicon.ico")))
+ .Times(1)
+ .WillOnce(testing::Invoke(CBF(&cfd, &MockCFDelegate::Reply404)));
+
+ EXPECT_CALL(cfd, OnRequestRead(tab_id, request_id, testing::_))
+ .Times(testing::AtMost(1));
+
+ bool incognito = true;
+ EXPECT_TRUE(client->Initialize(&cfd, timeout, false, profile, L"",
+ incognito));
+
+ loop.RunFor(10);
+ client->Uninitialize();
+ client.reset(NULL);
+}
+
+
+// [CFAC] -- uses a ProxyFactory for creation of ChromeFrameAutomationProxy
+// -- uses ChromeFrameAutomationProxy
+// -- uses TabProxy obtained from ChromeFrameAutomationProxy
+// -- uses ChromeFrameDelegate as outgoing interface
+//
+// We mock ProxyFactory to return mock object (MockAutomationProxy) implementing
+// ChromeFrameAutomationProxy interface.
+// Since CFAC uses TabProxy for few calls and TabProxy is not easy mockable,
+// we create 'real' TabProxy but with fake AutomationSender (the one responsible
+// for sending messages over channel).
+// Additionally we have mock implementation ChromeFrameDelagate interface -
+// MockCFDelegate.
+
+// Test fixture, saves typing all of it's members.
+class CFACMockTest : public testing::Test {
+ public:
+ MockProxyFactory factory_;
+ MockCFDelegate cfd_;
+ TimedMsgLoop loop_;
+ MockAutomationProxy proxy_;
+ scoped_ptr<AutomationHandleTracker> tracker_;
+ MockAutomationMessageSender dummy_sender_;
+ scoped_refptr<TabProxy> tab_;
+ scoped_ptr<ChromeFrameAutomationClient> client_; // the victim of all tests
+
+ std::wstring profile_;
+ int timeout_;
+ void* id_; // Automation server id we are going to return
+ int tab_handle_; // Tab handle. Any non-zero value is Ok.
+
+ inline ChromeFrameAutomationProxy* get_proxy() {
+ return static_cast<ChromeFrameAutomationProxy*>(&proxy_);
+ }
+
+ inline void CreateTab() {
+ ASSERT_EQ(NULL, tab_.get());
+ tab_ = new TabProxy(&dummy_sender_, tracker_.get(), tab_handle_);
+ }
+
+ // Easy methods to set expectations.
+ void SetAutomationServerOk() {
+ EXPECT_CALL(factory_, GetAutomationServer(testing::Eq(timeout_),
+ testing::StrEq(profile_),
+ testing::_,
+ testing::_,
+ testing::NotNull()))
+ .Times(1)
+ .WillOnce(testing::DoAll(
+ testing::WithArgs<0, 4>(
+ testing::Invoke(CBF(&factory_, &MockProxyFactory::GetServerImpl,
+ get_proxy(), AUTOMATION_SUCCESS))),
+ testing::Return(id_)));
+
+ EXPECT_CALL(factory_, ReleaseAutomationServer(testing::Eq(id_))).Times(1);
+ }
+
+ void Set_CFD_LaunchFailed(AutomationLaunchResult result) {
+ EXPECT_CALL(cfd_, OnAutomationServerLaunchFailed(
+ testing::Eq(result), testing::_))
+ .Times(1)
+ .WillOnce(QUIT_LOOP(loop_));
+ }
+
+ protected:
+ CFACMockTest() : tracker_(NULL), timeout_(500),
+ profile_(L"Adam.N.Epilinter") {
+ id_ = reinterpret_cast<void*>(5);
+ tab_handle_ = 3;
+ }
+
+ virtual void SetUp() {
+ dummy_sender_.ForwardTo(&proxy_);
+ tracker_.reset(new AutomationHandleTracker(&dummy_sender_));
+
+ client_.reset(new ChromeFrameAutomationClient);
+ client_->set_proxy_factory(&factory_);
+ }
+};
+
+// Could be implemented as MockAutomationProxy member (we have WithArgs<>!)
+ACTION_P3(HandleCreateTab, tab_handle, external_tab_container, tab_wnd) {
+ // arg0 - message
+ // arg1 - callback
+ // arg2 - key
+ CallbackRunner<Tuple3<HWND, HWND, int> >* c =
+ reinterpret_cast<CallbackRunner<Tuple3<HWND, HWND, int> >*>(arg1);
+ c->Run(external_tab_container, tab_wnd, tab_handle);
+ delete c;
+ delete arg0;
+}
+
+TEST_F(CFACMockTest, MockedCreateTabOk) {
+ int timeout = 500;
+ CreateTab();
+ SetAutomationServerOk();
+
+ EXPECT_CALL(proxy_, server_version()).Times(testing::AnyNumber())
+ .WillRepeatedly(testing::Return(""));
+
+ // We need some valid HWNDs, when responding to CreateExternalTab
+ HWND h1 = ::GetDesktopWindow();
+ HWND h2 = ::GetDesktopWindow();
+ EXPECT_CALL(proxy_, SendAsAsync(testing::Property(&IPC::SyncMessage::type,
+ AutomationMsg_CreateExternalTab__ID),
+ testing::NotNull(), testing::_))
+ .Times(1)
+ .WillOnce(HandleCreateTab(tab_handle_, h1, h2));
+
+ EXPECT_CALL(proxy_, CreateTabProxy(testing::Eq(tab_handle_)))
+ .WillOnce(testing::Return(tab_));
+
+ EXPECT_CALL(cfd_, OnAutomationServerReady())
+ .WillOnce(QUIT_LOOP(loop_));
+
+ // Here we go!
+ EXPECT_TRUE(client_->Initialize(&cfd_, timeout, false, profile_, L"", false));
+ loop_.RunFor(10);
+ client_->Uninitialize();
+}
+
+TEST_F(CFACMockTest, MockedCreateTabFailed) {
+ HWND null_wnd = NULL;
+ SetAutomationServerOk();
+
+ EXPECT_CALL(proxy_, server_version()).Times(testing::AnyNumber())
+ .WillRepeatedly(testing::Return(""));
+
+ EXPECT_CALL(proxy_, SendAsAsync(testing::Property(&IPC::SyncMessage::type,
+ AutomationMsg_CreateExternalTab__ID),
+ testing::NotNull(), testing::_))
+ .Times(1)
+ .WillOnce(HandleCreateTab(tab_handle_, null_wnd, null_wnd));
+
+ EXPECT_CALL(proxy_, CreateTabProxy(testing::_)).Times(0);
+
+ Set_CFD_LaunchFailed(AUTOMATION_CREATE_TAB_FAILED);
+
+ // Here we go!
+ EXPECT_TRUE(client_->Initialize(&cfd_, timeout_, false, profile_, L"",
+ false));
+ loop_.RunFor(4);
+ client_->Uninitialize();
+}
+
+const wchar_t kMetaTagPage[] = L"files/meta_tag.html";
+TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_MetaTag) {
+ SimpleBrowserTest(IE, kMetaTagPage, L"meta_tag");
+}
+
+const wchar_t kCFProtocolPage[] = L"files/chrome_frame_protocol.html";
+TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_CFProtocol) {
+ SimpleBrowserTest(IE, kCFProtocolPage, L"chrome_frame_protocol");
+}
+
+const wchar_t kPersistentCookieTest[] =
+ L"files/persistent_cookie_test_page.html";
+TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_PersistentCookieTest) {
+ SimpleBrowserTest(IE, kPersistentCookieTest, L"PersistentCookieTest");
+}
+
+const wchar_t kNavigateOutPage[] = L"files/navigate_out.html";
+TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_NavigateOut) {
+ SimpleBrowserTest(IE, kNavigateOutPage, L"navigate_out");
+}
+
+HRESULT LaunchIEAsComServer(IWebBrowser2** web_browser) {
+ if (!web_browser)
+ return E_INVALIDARG;
+
+ ScopedComPtr<IWebBrowser2> web_browser2;
+ HRESULT hr = CoCreateInstance(
+ CLSID_InternetExplorer, NULL, CLSCTX_LOCAL_SERVER, IID_IWebBrowser2,
+ reinterpret_cast<void**>(web_browser2.Receive()));
+
+ if (SUCCEEDED(hr)) {
+ *web_browser = web_browser2.Detach();
+ }
+
+ return hr;
+}
+
+TEST(ChromeFrameTest, FullTabModeIE_DisallowedUrls) {
+ int major_version = 0;
+ int minor_version = 0;
+ int bugfix_version = 0;
+
+ base::SysInfo::OperatingSystemVersionNumbers(&major_version, &minor_version,
+ &bugfix_version);
+ if (major_version > 5) {
+ DLOG(INFO) << __FUNCTION__ << " Not running test on Windows version: "
+ << major_version;
+ return;
+ }
+
+ IEVersion ie_version = GetIEVersion();
+ if (ie_version == IE_8) {
+ DLOG(INFO) << __FUNCTION__ << " Not running test on IE8";
+ return;
+ }
+
+ HRESULT hr = CoInitialize(NULL);
+ bool should_uninit = SUCCEEDED(hr);
+
+ ScopedComPtr<IWebBrowser2> web_browser2;
+ EXPECT_TRUE(S_OK == LaunchIEAsComServer(web_browser2.Receive()));
+ web_browser2->put_Visible(VARIANT_TRUE);
+
+ CComObject<WebBrowserEventSink>* web_browser_sink = NULL;
+ CComObject<WebBrowserEventSink>::CreateInstance(&web_browser_sink);
+
+ // Pass the main thread id to the browser sink so that it can notify
+ // us about test completion.
+ web_browser_sink->set_main_thread_id(GetCurrentThreadId());
+
+ hr = web_browser_sink->DispEventAdvise(web_browser2,
+ &DIID_DWebBrowserEvents2);
+ EXPECT_TRUE(hr == S_OK);
+
+ VARIANT empty = ScopedVariant::kEmptyVariant;
+ ScopedVariant url;
+ url.Set(L"cf:file:///C:/");
+
+ TimedMsgLoop loop;
+
+ hr = web_browser2->Navigate2(url.AsInput(), &empty, &empty, &empty, &empty);
+ EXPECT_TRUE(hr == S_OK);
+
+ loop.RunFor(10);
+
+ EXPECT_TRUE(web_browser_sink->navigation_failed());
+
+ hr = web_browser_sink->DispEventUnadvise(web_browser2);
+ EXPECT_TRUE(hr == S_OK);
+
+ web_browser2.Release();
+ chrome_frame_test::CloseAllIEWindows();
+
+ if (should_uninit) {
+ CoUninitialize();
+ }
+}
+