summaryrefslogtreecommitdiffstats
path: root/chrome_frame
diff options
context:
space:
mode:
authorjoi@chromium.org <joi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-11-10 01:14:41 +0000
committerjoi@chromium.org <joi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-11-10 01:14:41 +0000
commitf30e74751217091c0b6050080f46cd6eb4914226 (patch)
treea2dcb8e715d1578698856e38c36459602dc19732 /chrome_frame
parent9b2ab5910c58603ec655bb613bec7596e732f87b (diff)
downloadchromium_src-f30e74751217091c0b6050080f46cd6eb4914226.zip
chromium_src-f30e74751217091c0b6050080f46cd6eb4914226.tar.gz
chromium_src-f30e74751217091c0b6050080f46cd6eb4914226.tar.bz2
Adding a privileged callback used in IE CF to check whether to show
the version mismatch warning dialog. Used this in ceee/ to only show it once per tab. Changed the logic in Firefox to show the warning dialog even when in privileged mode. This will mean it gets shown once per Firefox window. Wrote a unit test for the additional logic in ChromeFrameActivex. To write the unit test, used com_mock.py to generate a mock of the IChromeFramePrivileged interface. This can be extended to generate mocks of the other CF interfaces. Discovered duplication of np_browser_functions.h and .cc, resolved this to a single copy (the one under chrome_frame). Changed things around so chrome_tab.idl is built only once; this also lets me more easily depend on it in the com_mock rule. BUG=none TEST=chrome_frame_unittests.exe Review URL: http://codereview.chromium.org/4563001 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@65613 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome_frame')
-rw-r--r--chrome_frame/chrome_frame.gyp116
-rw-r--r--chrome_frame/chrome_frame_activex.cc28
-rw-r--r--chrome_frame/chrome_frame_activex.h4
-rw-r--r--chrome_frame/chrome_frame_npapi.cc8
-rw-r--r--chrome_frame/chrome_tab.idl6
-rw-r--r--chrome_frame/np_browser_functions.h32
-rw-r--r--chrome_frame/test/chrome_frame_activex_unittest.cc100
-rw-r--r--chrome_frame/test/chrome_tab_mocks.h41
8 files changed, 294 insertions, 41 deletions
diff --git a/chrome_frame/chrome_frame.gyp b/chrome_frame/chrome_frame.gyp
index d31e990..0cfe895 100644
--- a/chrome_frame/chrome_frame.gyp
+++ b/chrome_frame/chrome_frame.gyp
@@ -27,7 +27,7 @@
'<(xul_sdk_dir)/include/string',
'<(xul_sdk_dir)/include/xpcom',
'<(xul_sdk_dir)/include/xpconnect',
- ],
+ ],
'conditions': [
['OS=="win"', {
'python': [
@@ -88,18 +88,73 @@
],
},
{
+ # Builds our IDL file to the shared intermediate directory.
+ 'target_name': 'chrome_tab_idl',
+ 'type': 'none',
+ 'msvs_settings': {
+ 'VCMIDLTool': {
+ 'OutputDirectory': '<(SHARED_INTERMEDIATE_DIR)',
+ },
+ },
+ 'sources': [
+ 'chrome_tab.idl',
+ ],
+ # Add the output dir for those who depend on us.
+ 'direct_dependent_settings': {
+ 'include_dirs': ['<(SHARED_INTERMEDIATE_DIR)'],
+ },
+ },
+ {
+ 'target_name': 'chrome_frame_privileged_mock',
+ 'type': 'none',
+ 'dependencies': [
+ 'chrome_tab_idl',
+ ],
+ 'sources': [
+ '../ceee/testing/utils/com_mock.py',
+ '<(SHARED_INTERMEDIATE_DIR)/chrome_tab.h',
+ ],
+ 'actions': [
+ {
+ 'action_name': 'make_chrome_frame_privileged_mock',
+ 'msvs_cygwin_shell': 0,
+ 'msvs_quote_cmd': 0,
+ 'inputs': [
+ '../ceee/testing/utils/com_mock.py',
+ ],
+ 'outputs': [
+ '<(SHARED_INTERMEDIATE_DIR)/mock_ichromeframeprivileged.gen',
+ ],
+ 'action': [
+ '<@(python)',
+ '../ceee/testing/utils/com_mock.py',
+ 'IChromeFramePrivileged',
+ '<(SHARED_INTERMEDIATE_DIR)/chrome_tab.h',
+ '> "<(SHARED_INTERMEDIATE_DIR)/mock_ichromeframeprivileged.gen"',
+ ],
+ },
+ ],
+ # All who use this need to be able to find the .gen file we generate.
+ 'all_dependent_settings': {
+ 'include_dirs': ['<(SHARED_INTERMEDIATE_DIR)'],
+ },
+ },
+ {
'target_name': 'chrome_frame_unittests',
'type': 'executable',
'dependencies': [
'../base/base.gyp:test_support_base',
+ '../ceee/ie/common/common.gyp:ie_common',
+ '../ceee/testing/utils/test_utils.gyp:test_utils',
'../testing/gmock.gyp:gmock',
'../testing/gtest.gyp:gtest',
'chrome_frame_ie',
+ 'chrome_frame_privileged_mock',
'chrome_frame_strings',
+ 'chrome_tab_idl',
],
'sources': [
'chrome_tab.h',
- 'chrome_tab.idl',
'chrome_frame_histograms.h',
'chrome_frame_histograms.cc',
'chrome_frame_unittest_main.cc',
@@ -108,6 +163,8 @@
'chrome_launcher_unittest.cc',
'function_stub_unittest.cc',
'renderer_glue.cc',
+ 'test/chrome_frame_activex_unittest.cc',
+ 'test/chrome_tab_mocks.h',
'test/chrome_frame_test_utils.h',
'test/chrome_frame_test_utils.cc',
'test/com_message_event_unittest.cc',
@@ -129,10 +186,6 @@
'urlmon_upload_data_stream_unittest.cc',
'vtable_patch_manager_unittest.cc',
],
- 'include_dirs': [
- # To allow including "chrome_tab.h"
- '<(INTERMEDIATE_DIR)',
- ],
'resource_include_dirs': [
'<(INTERMEDIATE_DIR)',
'<(SHARED_INTERMEDIATE_DIR)',
@@ -162,7 +215,7 @@
'../chrome/chrome.gyp:automation',
],
}],
- ],
+ ],
}],
['OS=="win"', {
'link_settings': {
@@ -214,6 +267,7 @@
'chrome_frame_npapi',
'chrome_frame_strings',
'chrome_frame_utils',
+ 'chrome_tab_idl',
'npchrome_frame',
'xulrunner_sdk',
],
@@ -258,15 +312,12 @@
'test/win_event_receiver.h',
'chrome_launcher_version.rc',
'chrome_tab.h',
- 'chrome_tab.idl',
'test_utils.cc',
'test_utils.h',
],
'include_dirs': [
'<@(xul_include_directories)',
'<(DEPTH)/third_party/wtl/include',
- # To allow including "chrome_tab.h"
- '<(INTERMEDIATE_DIR)',
],
'resource_include_dirs': [
'<(INTERMEDIATE_DIR)',
@@ -330,6 +381,7 @@
'chrome_frame_npapi',
'chrome_frame_strings',
'chrome_frame_utils',
+ 'chrome_tab_idl',
'npchrome_frame',
'xulrunner_sdk',
],
@@ -341,7 +393,6 @@
'../chrome/test/chrome_process_util.h',
'../chrome/test/ui/ui_test.cc',
'chrome_tab.h',
- 'chrome_tab.idl',
'test/chrome_frame_test_utils.cc',
'test/chrome_frame_test_utils.h',
'test/perf/chrome_frame_perftest.cc',
@@ -358,8 +409,6 @@
'include_dirs': [
'<@(xul_include_directories)',
'<(DEPTH)/third_party/wtl/include',
- # To allow including "chrome_tab.h"
- '<(INTERMEDIATE_DIR)',
],
'conditions': [
['OS=="win"', {
@@ -409,6 +458,7 @@
'../third_party/icu/icu.gyp:icuuc',
'chrome_frame_npapi',
'chrome_frame_ie',
+ 'chrome_tab_idl',
'npchrome_frame',
],
'sources': [
@@ -431,11 +481,6 @@
'test/net/test_automation_resource_message_filter.cc',
'test/net/test_automation_resource_message_filter.h',
'chrome_tab.h',
- 'chrome_tab.idl',
- ],
- 'include_dirs': [
- # To allow including "chrome_tab.h"
- '<(INTERMEDIATE_DIR)',
],
'conditions': [
['OS=="win"', {
@@ -486,6 +531,7 @@
'chrome_frame_ie',
'chrome_frame_npapi',
'chrome_frame_strings',
+ 'chrome_tab_idl',
],
'sources': [
'test/reliability/run_all_unittests.cc',
@@ -503,7 +549,6 @@
'test/win_event_receiver.cc',
'test/win_event_receiver.h',
'chrome_tab.h',
- 'chrome_tab.idl',
'../base/test/test_file_util_win.cc',
'../chrome/test/ui/ui_test.cc',
'../chrome/test/ui/ui_test_suite.cc',
@@ -511,10 +556,6 @@
'../chrome/test/chrome_process_util.cc',
'../chrome/test/chrome_process_util.h',
],
- 'include_dirs': [
- # To allow including "chrome_tab.h"
- '<(INTERMEDIATE_DIR)',
- ],
'resource_include_dirs': [
'<(INTERMEDIATE_DIR)',
],
@@ -543,12 +584,23 @@
}],
],
},
-
+ {
+ 'target_name': 'chrome_frame_npapi_core',
+ 'type': 'static_library',
+ 'dependencies': [
+ '../base/base.gyp:base',
+ ],
+ 'sources': [
+ 'np_browser_functions.cc',
+ 'np_browser_functions.h',
+ ],
+ },
{
'target_name': 'chrome_frame_npapi',
'type': 'static_library',
'dependencies': [
'chrome_frame_common',
+ 'chrome_frame_npapi_core',
'chrome_frame_strings',
'chrome_frame_utils',
'../chrome/chrome.gyp:common',
@@ -559,8 +611,6 @@
'chrome_frame_npapi.h',
'ff_30_privilege_check.cc',
'ff_privilege_check.h',
- 'np_browser_functions.cc',
- 'np_browser_functions.h',
'np_event_listener.cc',
'np_event_listener.h',
'np_proxy_service.cc',
@@ -591,7 +641,7 @@
'<(SHARED_INTERMEDIATE_DIR)/chrome_frame/grit/<(RULE_INPUT_ROOT).h',
'<(SHARED_INTERMEDIATE_DIR)/chrome_frame/<(RULE_INPUT_ROOT).pak',
],
- 'action': ['python', '<@(_inputs)', '-i',
+ 'action': ['python', '<@(_inputs)', '-i',
'<(RULE_INPUT_PATH)',
'build', '-o', '<(grit_out_dir)'
],
@@ -624,7 +674,7 @@
'../chrome/chrome.gyp:chrome_version_header',
],
'include_dirs': [
- # To allow including "chrome_tab.h"
+ # To allow including "version.h"
'<(SHARED_INTERMEDIATE_DIR)',
],
'sources': [
@@ -641,6 +691,7 @@
'chrome_frame_common',
'chrome_frame_strings',
'chrome_frame_utils',
+ 'chrome_tab_idl',
'../chrome/chrome.gyp:common',
'../chrome/chrome.gyp:utility',
'../build/temp_gyp/googleurl.gyp:googleurl',
@@ -671,7 +722,6 @@
'chrome_protocol.h',
'chrome_protocol.rgs',
'chrome_tab.h',
- 'chrome_tab.idl',
'com_message_event.cc',
'com_message_event.h',
'com_type_info_holder.cc',
@@ -719,8 +769,6 @@
'vtable_patch_manager.h',
],
'include_dirs': [
- # To allow including "chrome_tab.h"
- '<(INTERMEDIATE_DIR)',
'<(INTERMEDIATE_DIR)/../chrome_frame',
'<(DEPTH)/third_party/wtl/include',
],
@@ -808,6 +856,7 @@
'chrome_frame_npapi',
'chrome_frame_strings',
'chrome_frame_utils',
+ 'chrome_tab_idl',
'xulrunner_sdk',
'chrome_frame_launcher.gyp:chrome_launcher',
'../build/temp_gyp/googleurl.gyp:googleurl',
@@ -828,7 +877,6 @@
'chrome_tab.cc',
'chrome_tab.def',
'chrome_tab.h',
- 'chrome_tab.idl',
# FIXME(slightlyoff): For chrome_tab.tlb. Giant hack until we can
# figure out something more gyp-ish.
'resources/tlb_resource.rc',
@@ -838,8 +886,6 @@
'resource.h',
],
'include_dirs': [
- # To allow including "chrome_tab.h"
- '<(INTERMEDIATE_DIR)',
'<(INTERMEDIATE_DIR)/../npchrome_frame',
],
'conditions': [
@@ -936,7 +982,7 @@
# TODO(mad): FIX THIS!
#'chrome_frame_net_tests',
#'chrome_frame_reliability_tests',
-
+
# Other tests depend on Chrome bins being available when they run.
# Those should be re-enabled as soon as we setup the build slave to
# also build (or download an archive of) Chrome, even it it isn't
diff --git a/chrome_frame/chrome_frame_activex.cc b/chrome_frame/chrome_frame_activex.cc
index a5d6d99..6085546 100644
--- a/chrome_frame/chrome_frame_activex.cc
+++ b/chrome_frame/chrome_frame_activex.cc
@@ -246,13 +246,35 @@ void ChromeFrameActivex::OnMessageFromChromeFrame(int tab_handle,
}
}
+bool ChromeFrameActivex::ShouldShowVersionMismatchDialog(
+ bool is_privileged,
+ IOleClientSite* client_site) {
+ if (!is_privileged) {
+ return true;
+ }
+
+ if (client_site) {
+ ScopedComPtr<IChromeFramePrivileged> service;
+ HRESULT hr = DoQueryService(SID_ChromeFramePrivileged,
+ client_site,
+ service.Receive());
+ if (SUCCEEDED(hr) && service) {
+ return (S_FALSE != service->ShouldShowVersionMismatchDialog());
+ }
+ }
+
+ NOTREACHED();
+ return true;
+}
+
void ChromeFrameActivex::OnAutomationServerLaunchFailed(
AutomationLaunchResult reason, const std::string& server_version) {
Base::OnAutomationServerLaunchFailed(reason, server_version);
- // Do not display warnings for privileged instances of Chrome Frame.
- if (reason == AUTOMATION_VERSION_MISMATCH && !is_privileged_) {
- THREAD_SAFE_UMA_HISTOGRAM_COUNTS("ChromeFrame.VersionMismatchDisplayed", 1);
+ if (reason == AUTOMATION_VERSION_MISMATCH &&
+ ShouldShowVersionMismatchDialog(is_privileged_, m_spClientSite)) {
+ THREAD_SAFE_UMA_HISTOGRAM_COUNTS(
+ "ChromeFrame.VersionMismatchDisplayed", 1);
DisplayVersionMismatchWarning(m_hWnd, server_version);
}
}
diff --git a/chrome_frame/chrome_frame_activex.h b/chrome_frame/chrome_frame_activex.h
index 21ded83..8fee559 100644
--- a/chrome_frame/chrome_frame_activex.h
+++ b/chrome_frame/chrome_frame_activex.h
@@ -105,6 +105,10 @@ END_MSG_MAP()
const std::vector<FilePath>& extension_directories);
virtual void OnChannelError();
+ // Separated to static function for unit testing this logic more easily.
+ static bool ShouldShowVersionMismatchDialog(bool is_privileged,
+ IOleClientSite* client_site);
+
private:
LRESULT OnCreate(UINT message, WPARAM wparam, LPARAM lparam,
BOOL& handled); // NO_LINT
diff --git a/chrome_frame/chrome_frame_npapi.cc b/chrome_frame/chrome_frame_npapi.cc
index 5668a5b..ea7217f 100644
--- a/chrome_frame/chrome_frame_npapi.cc
+++ b/chrome_frame/chrome_frame_npapi.cc
@@ -882,8 +882,12 @@ void ChromeFrameNPAPI::OnAutomationServerLaunchFailed(
AutomationLaunchResult reason, const std::string& server_version) {
SetReadyState(READYSTATE_UNINITIALIZED);
- // Do not display warnings for privileged instances of Chrome Frame.
- if (reason == AUTOMATION_VERSION_MISMATCH && !is_privileged_) {
+ // In IE, we don't display warnings for privileged CF instances because
+ // there are 2 CFs created for each tab (so we decide on the CEEE side
+ // whether to show a warning). In FF however, there is only one privileged
+ // CF instance per Firefox window, so OK to show the warning there without
+ // any further logic.
+ if (reason == AUTOMATION_VERSION_MISMATCH) {
THREAD_SAFE_UMA_HISTOGRAM_COUNTS("ChromeFrame.VersionMismatchDisplayed", 1);
DisplayVersionMismatchWarning(m_hWnd, server_version);
}
diff --git a/chrome_frame/chrome_tab.idl b/chrome_frame/chrome_tab.idl
index 7120910..5f3dcbb 100644
--- a/chrome_frame/chrome_tab.idl
+++ b/chrome_frame/chrome_tab.idl
@@ -95,7 +95,7 @@ interface IChromeFrameInternal : IUnknown {
[
object,
- uuid(655A11E0-EF63-4fbe-9DF6-C182D2FCD6DC),
+ uuid(8AD52429-3CE0-4883-BC69-2DFA055D20D4),
oleautomation,
nonextensible,
hidden,
@@ -113,6 +113,10 @@ interface IChromeFramePrivileged : IUnknown {
// Return S_FALSE to leave the default, which is to not automate any
// functions.
HRESULT GetExtensionApisToAutomate([out] BSTR *extension_apis);
+ // Called when an automation version mismatch occurs. Returns S_OK if
+ // a dialog should be showed to the user by this CF instance, S_FALSE if
+ // not.
+ HRESULT ShouldShowVersionMismatchDialog();
};
// Expose this service to the ChromeFrame control to trigger privileged
diff --git a/chrome_frame/np_browser_functions.h b/chrome_frame/np_browser_functions.h
index 1a85cee..b2dbd74 100644
--- a/chrome_frame/np_browser_functions.h
+++ b/chrome_frame/np_browser_functions.h
@@ -233,6 +233,38 @@ class ScopedNpObject {
return npo_;
}
+ bool Invoke0(NPP npp, NPIdentifier id, NPVariant* result) {
+ return npapi::Invoke(npp, npo_, id, NULL, 0, result);
+ }
+ bool Invoke0(NPP npp, const NPUTF8* name, NPVariant* result) {
+ return Invoke0(npp, npapi::GetStringIdentifier(name), result);
+ }
+
+ bool Invoke1(NPP npp, NPIdentifier id, const NPVariant &arg1,
+ NPVariant* result) {
+ return npapi::Invoke(npp, npo_, id, &arg1, 1, result);
+ }
+ bool Invoke1(NPP npp, const NPUTF8* name, const NPVariant &arg1,
+ NPVariant* result) {
+ return Invoke1(npp, npapi::GetStringIdentifier(name), arg1, result);
+ }
+ bool InvokeN(NPP npp, NPIdentifier id, const NPVariant* args, unsigned argc,
+ NPVariant* result) {
+ return npapi::Invoke(npp, npo_, id, args, argc, result);
+ }
+ bool InvokeN(NPP npp, const NPUTF8* name, const NPVariant* args,
+ unsigned argc, NPVariant* result) {
+ return Invoke1(npp, npapi::GetStringIdentifier(name), args, argc, result);
+ }
+
+ bool GetProperty(NPP npp, NPIdentifier id, NPVariant* result) {
+ return npapi::GetProperty(npp, npo_, id, result);
+ }
+
+ bool GetProperty(NPP npp, const NPUTF8* name, NPVariant* result) {
+ return GetProperty(npp, npapi::GetStringIdentifier(name), result);
+ }
+
private:
NpoType* npo_;
DISALLOW_COPY_AND_ASSIGN(ScopedNpObject);
diff --git a/chrome_frame/test/chrome_frame_activex_unittest.cc b/chrome_frame/test/chrome_frame_activex_unittest.cc
new file mode 100644
index 0000000..93f570f
--- /dev/null
+++ b/chrome_frame/test/chrome_frame_activex_unittest.cc
@@ -0,0 +1,100 @@
+// 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.
+//
+// Unit tests for ChromeFrameActivex.
+
+#include "chrome_frame/chrome_frame_activex.h"
+
+#include "ceee/common/initializing_coclass.h"
+#include "ceee/testing/utils/test_utils.h"
+#include "ceee/testing/utils/mock_com.h"
+#include "chrome_frame/test/chrome_tab_mocks.h"
+#include "gtest/gtest.h"
+#include "gmock/gmock.h"
+
+namespace {
+
+using testing::_;
+using testing::AddRef;
+using testing::DoAll;
+using testing::IOleClientSiteMockImpl;
+using testing::IServiceProviderMockImpl;
+using testing::MockIChromeFramePrivileged;
+using testing::Return;
+using testing::SetArgumentPointee;
+using testing::StrictMock;
+
+// Just to unhide the static function.
+class TestingChromeFrameActivex : public ChromeFrameActivex {
+ public:
+ static HRESULT TestingShouldShowVersionMismatchDialog(
+ bool is_privileged, IOleClientSite* client_site) {
+ return ShouldShowVersionMismatchDialog(is_privileged, client_site);
+ }
+};
+
+class MockChromeFrameClientSite
+ : public CComObjectRootEx<CComSingleThreadModel>,
+ public StrictMock<IOleClientSiteMockImpl>,
+ public StrictMock<IServiceProviderMockImpl> {
+ public:
+ DECLARE_NOT_AGGREGATABLE(MockChromeFrameClientSite)
+ BEGIN_COM_MAP(MockChromeFrameClientSite)
+ COM_INTERFACE_ENTRY(IOleClientSite)
+ COM_INTERFACE_ENTRY(IServiceProvider)
+ END_COM_MAP()
+ DECLARE_PROTECT_FINAL_CONSTRUCT()
+
+ HRESULT Initialize(MockChromeFrameClientSite** client_site) {
+ *client_site = this;
+ return S_OK;
+ }
+};
+
+TEST(ChromeFrameActivex, ShouldShowVersionMismatchDialog) {
+ // If not privileged, we always show the dialog.
+ ASSERT_TRUE(
+ TestingChromeFrameActivex::TestingShouldShowVersionMismatchDialog(
+ false, NULL));
+
+ MockChromeFrameClientSite* cs_keeper;
+ ScopedComPtr<IOleClientSite> cs;
+ ASSERT_HRESULT_SUCCEEDED(
+ InitializingCoClass<MockChromeFrameClientSite>::CreateInitialized(
+ &cs_keeper, cs.Receive()));
+
+ MockIChromeFramePrivileged* cfp_keeper;
+ ScopedComPtr<IChromeFramePrivileged> cfp;
+ ASSERT_HRESULT_SUCCEEDED(
+ InitializingCoClass<MockIChromeFramePrivileged>::CreateInitialized(
+ &cfp_keeper, cfp.Receive()));
+
+ EXPECT_CALL(*cs_keeper, QueryService(SID_ChromeFramePrivileged,
+ IID_IChromeFramePrivileged, _))
+ .WillRepeatedly(DoAll(AddRef(cfp.get()),
+ SetArgumentPointee<2>(static_cast<void*>(cfp)),
+ Return(S_OK)));
+
+ EXPECT_CALL(*cfp_keeper, ShouldShowVersionMismatchDialog())
+ .WillOnce(Return(S_OK));
+ ASSERT_TRUE(
+ TestingChromeFrameActivex::TestingShouldShowVersionMismatchDialog(
+ true, cs_keeper));
+
+ EXPECT_CALL(*cfp_keeper, ShouldShowVersionMismatchDialog())
+ .WillOnce(Return(S_FALSE));
+ ASSERT_FALSE(
+ TestingChromeFrameActivex::TestingShouldShowVersionMismatchDialog(
+ true, cs_keeper));
+
+ // Also test that we fail safe, showing the dialog unless we got
+ // an affirmative do-not-show.
+ EXPECT_CALL(*cfp_keeper, ShouldShowVersionMismatchDialog())
+ .WillOnce(Return(E_UNEXPECTED));
+ ASSERT_TRUE(
+ TestingChromeFrameActivex::TestingShouldShowVersionMismatchDialog(
+ true, cs_keeper));
+}
+
+} // namespace
diff --git a/chrome_frame/test/chrome_tab_mocks.h b/chrome_frame/test/chrome_tab_mocks.h
new file mode 100644
index 0000000..49e9809
--- /dev/null
+++ b/chrome_frame/test/chrome_tab_mocks.h
@@ -0,0 +1,41 @@
+// 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.
+//
+// Mock objects for Chrome Frame interfaces.
+
+#ifndef CHROME_FRAME_TEST_CHROME_TAB_MOCKS_H_
+#define CHROME_FRAME_TEST_CHROME_TAB_MOCKS_H_
+
+#include "testing/gmock/include/gmock/gmock.h"
+
+// Include without path to make GYP build see it.
+#include "chrome_tab.h" // NOLINT
+
+namespace testing {
+
+class IChromeFramePrivilegedMockImpl : public IChromeFramePrivileged {
+ public:
+ // Auto-generated by target chrome_frame_privileged_mock
+#include "mock_ichromeframeprivileged.gen" // NOLINT
+};
+
+class MockIChromeFramePrivileged
+ : public CComObjectRootEx<CComSingleThreadModel>,
+ public testing::StrictMock<IChromeFramePrivilegedMockImpl> {
+ public:
+ DECLARE_NOT_AGGREGATABLE(MockIChromeFramePrivileged)
+ BEGIN_COM_MAP(MockIChromeFramePrivileged)
+ COM_INTERFACE_ENTRY(IChromeFramePrivileged)
+ END_COM_MAP()
+ DECLARE_PROTECT_FINAL_CONSTRUCT()
+
+ HRESULT Initialize(MockIChromeFramePrivileged** cfp) {
+ *cfp = this;
+ return S_OK;
+ }
+};
+
+} // namespace testing
+
+#endif // CHROME_FRAME_TEST_CHROME_TAB_MOCKS_H_