diff options
Diffstat (limited to 'chrome_frame')
-rw-r--r-- | chrome_frame/chrome_frame.gyp | 25 | ||||
-rw-r--r-- | chrome_frame/test/delete_chrome_history_test.cc | 250 | ||||
-rw-r--r-- | chrome_frame/test/mock_ie_event_sink_actions.h | 67 | ||||
-rw-r--r-- | chrome_frame/test/mock_ie_event_sink_test.h | 54 | ||||
-rw-r--r-- | chrome_frame/test/navigation_test.cc | 32 | ||||
-rw-r--r-- | chrome_frame/test/net/fake_external_tab.cc | 13 | ||||
-rw-r--r-- | chrome_frame/test/ui_test.cc | 67 | ||||
-rw-r--r-- | chrome_frame/test/win_event_receiver.cc | 191 | ||||
-rw-r--r-- | chrome_frame/test/win_event_receiver.h | 78 |
9 files changed, 128 insertions, 649 deletions
diff --git a/chrome_frame/chrome_frame.gyp b/chrome_frame/chrome_frame.gyp index 8f3d62e..3560f7f 100644 --- a/chrome_frame/chrome_frame.gyp +++ b/chrome_frame/chrome_frame.gyp @@ -226,9 +226,6 @@ '../build/temp_gyp/googleurl.gyp:googleurl', '../chrome/chrome.gyp:common', '../chrome/chrome.gyp:utility', - '../chrome/chrome.gyp:browser', - '../chrome/chrome.gyp:debugger', - '../chrome/chrome.gyp:renderer', '../net/net.gyp:net_test_support', '../testing/gmock.gyp:gmock', '../testing/gtest.gyp:gtest', @@ -236,7 +233,7 @@ 'chrome_frame_ie', 'chrome_frame_npapi', 'chrome_frame_strings', - 'npchrome_frame', + 'npchrome_frame', 'xulrunner_sdk', ], 'sources': [ @@ -249,7 +246,6 @@ 'test/chrome_frame_ui_test_utils.h', 'test/chrome_frame_automation_mock.cc', 'test/chrome_frame_automation_mock.h', - 'test/delete_chrome_history_test.cc', 'test/http_server.cc', 'test/http_server.h', 'test/ie_event_sink.cc', @@ -276,6 +272,7 @@ 'test/win_event_receiver.h', 'chrome_tab.h', 'chrome_tab.idl', + 'renderer_glue.cc', 'test_utils.cc', 'test_utils.h', ], @@ -305,23 +302,7 @@ '../chrome/chrome.gyp:automation', '../chrome/chrome.gyp:installer_util', '../google_update/google_update.gyp:google_update', - ], - 'configurations': { - 'Debug_Base': { - 'msvs_settings': { - 'VCLinkerTool': { - 'LinkIncremental': '<(msvs_large_module_debug_link_mode)', - }, - }, - }, - }, - 'conditions': [ - ['win_use_allocator_shim==1', { - 'dependencies': [ - '../base/allocator/allocator.gyp:allocator', - ], - }], - ], + ] }], ], }, diff --git a/chrome_frame/test/delete_chrome_history_test.cc b/chrome_frame/test/delete_chrome_history_test.cc deleted file mode 100644 index 5f317f7..0000000 --- a/chrome_frame/test/delete_chrome_history_test.cc +++ /dev/null @@ -1,250 +0,0 @@ -// 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 <string> - -#include "base/rand_util.h" -#include "chrome/browser/webdata/web_database.h" -#include "chrome/common/url_constants.h" -#include "chrome/common/chrome_constants.h" -#include "chrome_frame/test/mock_ie_event_sink_actions.h" -#include "chrome_frame/test/mock_ie_event_sink_test.h" - -using testing::_; - -namespace chrome_frame_test { - -class DeleteBrowsingHistoryTest - : public MockIEEventSinkTest, - public testing::Test { - public: - DeleteBrowsingHistoryTest() {} - - virtual void SetUp() { - // We will use the OnAccLoad event to monitor page loads, so we ignore - // these. - ie_mock_.ExpectAnyNavigations(); - ie_mock2_.ExpectAnyNavigations(); - ie_mock3_.ExpectAnyNavigations(); - EXPECT_CALL(ie_mock_, OnLoad(_, _)).Times(testing::AnyNumber()); - EXPECT_CALL(ie_mock2_, OnLoad(_, _)).Times(testing::AnyNumber()); - EXPECT_CALL(ie_mock3_, OnLoad(_, _)).Times(testing::AnyNumber()); - - // Use a random image_path to ensure that a prior run does not - // interfere with our expectations about caching. - image_path_ = L"/" + RandomChars(32); - topHtml = - "<html><head>" - "<meta http-equiv=\"x-ua-compatible\" content=\"chrome=1\" />" - "</head>" - "<body>" - "<form method=\"POST\" action=\"/form\">" - "<input title=\"username\" type=\"text\" name=\"username\" />" - "<input type=\"submit\" title=\"Submit\" name=\"Submit\" />" - "</form>" - "<img alt=\"Blank image.\" src=\"" + WideToASCII(image_path_) + "\" />" - "This is some text.</body></html>"; - } - - protected: - std::wstring image_path_; - std::string topHtml; - - testing::NiceMock<MockAccEventObserver> acc_observer_; - MockWindowObserver delete_browsing_history_window_observer_mock_; - MockObjectWatcherDelegate ie_process_exit_watcher_mock_; - - testing::StrictMock<MockIEEventSink> ie_mock2_; - testing::StrictMock<MockIEEventSink> ie_mock3_; - - private: - // Returns a string of |count| lowercase random characters. - static std::wstring RandomChars(int count) { - srand(static_cast<unsigned int>(time(NULL))); - std::wstring str; - for (int i = 0; i < count; ++i) - str += L'a' + base::RandInt(0, 25); - return str; - } -}; - -namespace { - -const wchar_t* kFormFieldName = L"username"; -const wchar_t* kFormFieldValue = L"test_username"; - -const char* kHtmlHttpHeaders = - "HTTP/1.1 200 OK\r\n" - "Connection: close\r\n" - "Content-Type: text/html\r\n"; -const char* kFormResultHtml = - "<html><head><meta http-equiv=\"x-ua-compatible\" content=\"chrome=1\" />" - "</head><body>Nice work.</body></html>"; -const char* kBlankPngResponse[] = { - "HTTP/1.1 200 OK\r\n" - "Connection: close\r\n" - "Content-Type: image/png\r\n" - "Cache-Control: max-age=3600, must-revalidate\r\n", - "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52" - "\x00\x00\x00\x01\x00\x00\x00\x01\x01\x03\x00\x00\x00\x25\xdb\x56" - "\xca\x00\x00\x00\x03\x50\x4c\x54\x45\x00\x00\x00\xa7\x7a\x3d\xda" - "\x00\x00\x00\x01\x74\x52\x4e\x53\x00\x40\xe6\xd8\x66\x00\x00\x00" - "\x0a\x49\x44\x41\x54\x08\xd7\x63\x60\x00\x00\x00\x02\x00\x01\xe2" - "\x21\xbc\x33\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82"}; - -const size_t kBlankPngFileLength = 95; -} // anonymous namespace - -// Looks up |element_name| in the Chrome form data DB and ensures that the -// results match |matcher|. -ACTION_P2(ExpectFormValuesForElementNameMatch, element_name, matcher) { - FilePath profile_path( - chrome_frame_test::GetProfilePath(kIexploreProfileName) - .Append(L"Default").Append(chrome::kWebDataFilename)); - - WebDatabase web_database; - sql::InitStatus init_status = web_database.Init(profile_path); - EXPECT_EQ(sql::INIT_OK, init_status); - - if (init_status == sql::INIT_OK) { - std::vector<string16> values; - web_database.GetFormValuesForElementName(element_name, L"", &values, 9999); - EXPECT_THAT(values, matcher); - } -} - -// Launch |ie_mock| and navigate it to |url|. -ACTION_P2(LaunchThisIEAndNavigate, ie_mock, url) { - EXPECT_HRESULT_SUCCEEDED(ie_mock->event_sink()->LaunchIEAndNavigate(url, - ie_mock)); -} - -TEST_F(DeleteBrowsingHistoryTest, CFDeleteBrowsingHistory) { - if (GetInstalledIEVersion() < IE_8) { - LOG(ERROR) << "Test does not apply to IE versions < 8."; - return; - } - delete_browsing_history_window_observer_mock_.WatchWindow( - "Delete Browsing History"); - - EXPECT_CALL(server_mock_, Get(_, testing::StrEq(L"/top.html"), _)) - .WillRepeatedly(SendFast(kHtmlHttpHeaders, topHtml)); - EXPECT_CALL(server_mock_, Post(_, testing::StrEq(L"/form"), _)) - .WillRepeatedly(SendFast(kHtmlHttpHeaders, kFormResultHtml)); - - std::wstring top_url = server_mock_.Resolve(L"top.html"); - - testing::InSequence expect_in_sequence_for_scope; - - // First launch will hit the server, requesting top.html and then image_path_ - EXPECT_CALL(server_mock_, Get(_, testing::StrEq(image_path_), _)) - .WillOnce(SendFast(kBlankPngResponse[0], - std::string(kBlankPngResponse[1], - kBlankPngFileLength))); - - // top.html contains a form. Fill in the username field and submit, causing - // the value to be stored in Chrome's form data DB. - EXPECT_CALL(acc_observer_, OnAccDocLoad(_)) - .WillOnce(testing::DoAll( - AccLeftClickInRenderer(&ie_mock_, AccObjectMatcher(L"username")), - PostCharMessagesToRenderer(&ie_mock_, WideToASCII(kFormFieldValue)), - AccLeftClickInRenderer(&ie_mock_, AccObjectMatcher(L"Submit")))); - - // OnLoad of the result page from form submission. Now close the browser. - EXPECT_CALL(acc_observer_, OnAccDocLoad(_)) - .WillOnce(testing::DoAll( - WatchRendererProcess(&ie_process_exit_watcher_mock_, &ie_mock_), - CloseBrowserMock(&ie_mock_))); - - // Wait until the process is gone, so that the Chrome databases are unlocked. - EXPECT_CALL(ie_mock_, OnQuit()); - - // Verify that the submitted username is in the database, then launch a new - // IE instance. - EXPECT_CALL(ie_process_exit_watcher_mock_, OnObjectSignaled(_)) - .WillOnce(testing::DoAll( - ExpectFormValuesForElementNameMatch( - kFormFieldName, testing::Contains(kFormFieldValue)), - LaunchThisIEAndNavigate(&ie_mock2_, top_url))); - - // Second launch won't load the image due to the cache. - - // We do the delete private data twice, each time toggling the state of the - // 'Delete form data' and 'Delete temporary files' options. - // That's because we have no way to know their initial states. Using this, - // trick we are guaranteed to run it exactly once with each option turned on. - // Running it once with the option turned off is harmless. - - // Proceed to open up the "Safety" menu for the first time through the loop. - EXPECT_CALL(acc_observer_, OnAccDocLoad(_)) - .WillOnce(AccDoDefaultActionInBrowser(&ie_mock2_, - AccObjectMatcher(L"Safety"))); - - for (int i = 0; i < 2; ++i) { - // Watch for the popup menu, click 'Delete Browsing History...' - EXPECT_CALL(acc_observer_, OnMenuPopup(_)).WillOnce( - AccLeftClick(AccObjectMatcher(L"Delete Browsing History...*"))); - - // When it shows up, toggle the options and click "Delete". - EXPECT_CALL(delete_browsing_history_window_observer_mock_, OnWindowOpen(_)) - .WillOnce(testing::DoAll( - AccLeftClick(AccObjectMatcher(L"Temporary Internet files")), - AccLeftClick(AccObjectMatcher(L"Form data")), - AccLeftClick(AccObjectMatcher(L"Delete")))); - - // The configuration dialog closes. - EXPECT_CALL(delete_browsing_history_window_observer_mock_, - OnWindowClose(_)); - - // The progress dialog that pops up has the same caption. - EXPECT_CALL(delete_browsing_history_window_observer_mock_, - OnWindowOpen(_)); - - // Watch for it to go away, then close the browser. - if (i == 0) { - EXPECT_CALL(delete_browsing_history_window_observer_mock_, - OnWindowClose(_)).WillOnce(testing::DoAll( - AccExpectInRenderer(&ie_mock2_, - AccObjectMatcher(L"Blank image.")), - AccDoDefaultActionInBrowser(&ie_mock2_, - AccObjectMatcher(L"Safety")))); - } else { - EXPECT_CALL(delete_browsing_history_window_observer_mock_, - OnWindowClose(_)).WillOnce(testing::DoAll( - AccExpectInRenderer(&ie_mock2_, - AccObjectMatcher(L"Blank image.")), - CloseBrowserMock(&ie_mock2_))); - } - } - - // Close IE, wait for the process to exit... - EXPECT_CALL(ie_mock2_, OnQuit()) - .WillOnce(WatchBrowserProcess(&ie_process_exit_watcher_mock_, - &ie_mock2_)); - - // ... and verify that the remembered form data is not in the form data DB. - EXPECT_CALL(ie_process_exit_watcher_mock_, OnObjectSignaled(_)) - .WillOnce(testing::DoAll( - ExpectFormValuesForElementNameMatch( - kFormFieldName, testing::Not(testing::Contains(kFormFieldValue))), - LaunchThisIEAndNavigate(&ie_mock3_, top_url))); - - // Now that the cache is cleared, final session should load the image from the - // server. - EXPECT_CALL(server_mock_, Get(_, testing::StrEq(image_path_), _)).WillOnce( - SendFast(kBlankPngResponse[0], std::string(kBlankPngResponse[1], - kBlankPngFileLength))); - EXPECT_CALL(acc_observer_, OnAccDocLoad(_)) - .WillOnce(CloseBrowserMock(&ie_mock3_)); - EXPECT_CALL(ie_mock3_, OnQuit()).WillOnce(QUIT_LOOP(loop_)); - - // Start it up. Everything else is triggered as mock actions. - ASSERT_HRESULT_SUCCEEDED( - ie_mock_.event_sink()->LaunchIEAndNavigate(top_url, &ie_mock_)); - - // 3 navigations + 2 invocations of delete browser history == 5 - loop_.RunFor(kChromeFrameLongNavigationTimeoutInSeconds * 5); -} - -} // namespace chrome_frame_test diff --git a/chrome_frame/test/mock_ie_event_sink_actions.h b/chrome_frame/test/mock_ie_event_sink_actions.h index 7c9b38b..d6d8160 100644 --- a/chrome_frame/test/mock_ie_event_sink_actions.h +++ b/chrome_frame/test/mock_ie_event_sink_actions.h @@ -6,7 +6,6 @@ #define CHROME_FRAME_TEST_MOCK_IE_EVENT_SINK_ACTIONS_H_ #include <windows.h> -#include <string> #include "base/basictypes.h" #include "base/platform_thread.h" @@ -127,35 +126,28 @@ ACTION_P2(AccSetValue, matcher, value) { } } -namespace { // NOLINT -template<typename R> R AccInWindow(testing::Action<R(HWND)> action, HWND hwnd) { - return action.Perform(typename testing::Action<R(HWND)>::ArgumentTuple(hwnd)); -} -} - -ACTION_P2(AccDoDefaultActionInBrowser, mock, matcher) { - AccInWindow<void>(AccDoDefaultAction(matcher), - mock->event_sink()->GetBrowserWindow()); -} - ACTION_P2(AccDoDefaultActionInRenderer, mock, matcher) { - AccInWindow<void>(AccDoDefaultAction(matcher), - mock->event_sink()->GetRendererWindow()); + HWND window = mock->event_sink()->GetRendererWindow(); + scoped_refptr<AccObject> object; + if (FindAccObjectInWindow(window, matcher, &object)) { + EXPECT_TRUE(object->DoDefaultAction()); + } } ACTION_P2(AccLeftClickInBrowser, mock, matcher) { - AccInWindow<void>(AccLeftClick(matcher), - mock->event_sink()->GetBrowserWindow()); -} - -ACTION_P2(AccLeftClickInRenderer, mock, matcher) { - AccInWindow<void>(AccLeftClick(matcher), - mock->event_sink()->GetRendererWindow()); + HWND window = mock->event_sink()->GetBrowserWindow(); + scoped_refptr<AccObject> object; + if (FindAccObjectInWindow(window, matcher, &object)) { + EXPECT_TRUE(object->LeftClick()); + } } ACTION_P3(AccSetValueInBrowser, mock, matcher, value) { - AccInWindow<void>(AccSetValue(matcher, value), - mock->event_sink()->GetBrowserWindow()); + HWND window = mock->event_sink()->GetBrowserWindow(); + scoped_refptr<AccObject> object; + if (FindAccObjectInWindow(window, matcher, &object)) { + EXPECT_TRUE(object->SetValue(value)); + } } ACTION_P2(AccWatchForOneValueChange, observer, matcher) { @@ -180,8 +172,8 @@ ACTION_P(PostCharMessage, character_code) { } ACTION_P2(PostCharMessageToRenderer, mock, character_code) { - AccInWindow<void>(PostCharMessage(character_code), - mock->event_sink()->GetRendererWindow()); + HWND window = mock->event_sink()->GetRendererWindow(); + ::PostMessage(window, WM_CHAR, character_code, 0); } ACTION_P2(PostCharMessagesToRenderer, mock, character_codes) { @@ -199,21 +191,7 @@ ACTION_P(StopWindowWatching, mock) { mock->StopWatching(); } -ACTION_P(WatchWindowProcess, mock_observer) { - mock_observer->WatchProcessForHwnd(arg0); -} - -ACTION_P2(WatchBrowserProcess, mock_observer, mock) { - AccInWindow<void>(WatchWindowProcess(mock_observer), - mock->event_sink()->GetBrowserWindow()); -} - -ACTION_P2(WatchRendererProcess, mock_observer, mock) { - AccInWindow<void>(WatchWindowProcess(mock_observer), - mock->event_sink()->GetRendererWindow()); -} - -namespace { // NOLINT +namespace { void DoCloseWindowNow(HWND hwnd) { ::PostMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0); @@ -240,15 +218,6 @@ ACTION(KillChromeFrameProcesses) { } // Verifying actions -ACTION_P(AccExpect, matcher) { - scoped_refptr<AccObject> object; - EXPECT_TRUE(FindAccObjectInWindow(arg0, matcher, &object)); -} - -ACTION_P2(AccExpectInRenderer, mock, matcher) { - AccInWindow<void>(AccExpect(matcher), - mock->event_sink()->GetRendererWindow()); -} ACTION_P(ExpectRendererHasFocus, mock) { mock->event_sink()->ExpectRendererWindowHasFocus(); diff --git a/chrome_frame/test/mock_ie_event_sink_test.h b/chrome_frame/test/mock_ie_event_sink_test.h index 74be974..4a1e31d 100644 --- a/chrome_frame/test/mock_ie_event_sink_test.h +++ b/chrome_frame/test/mock_ie_event_sink_test.h @@ -8,7 +8,6 @@ #include <atlbase.h> #include <atlcom.h> #include <string> -#include <vector> #include "base/file_path.h" #include "base/string_number_conversions.h" @@ -204,55 +203,18 @@ class MockPropertyNotifySinkListener : public PropertyNotifySinkListener { ScopedComPtr<IUnknown> event_source_; }; -// Allows tests to observe when processes exit. -class MockObjectWatcherDelegate : public base::ObjectWatcher::Delegate { - public: - // base::ObjectWatcher::Delegate implementation - MOCK_METHOD1(OnObjectSignaled, void (HANDLE process_handle)); // NOLINT - - virtual ~MockObjectWatcherDelegate() { - // Would be nice to free them when OnObjectSignaled is called, too, but - // it doesn't seem worth it. - for (std::vector<HANDLE>::iterator it = process_handles_.begin(); - it != process_handles_.end(); ++it) { - ::CloseHandle(*it); - } - } - - // Registers this instance to watch |process_handle| for termination. - void WatchProcess(HANDLE process_handle) { - process_handles_.push_back(process_handle); - object_watcher_.StartWatching(process_handle, this); - } - - // Registers this instance to watch |hwnd|'s owning process for termination. - void WatchProcessForHwnd(HWND hwnd) { - DWORD pid = 0; - ::GetWindowThreadProcessId(hwnd, &pid); - EXPECT_TRUE(pid); - if (pid != 0) { - HANDLE process_handle = ::OpenProcess(SYNCHRONIZE, FALSE, pid); - EXPECT_TRUE(process_handle); - if (process_handle != NULL) { - WatchProcess(process_handle); - } - } - } - - private: - std::vector<HANDLE> process_handles_; - base::ObjectWatcher object_watcher_; -}; // Mocks a window observer so that tests can detect new windows. class MockWindowObserver : public WindowObserver { public: - // WindowObserver implementation - MOCK_METHOD1(OnWindowOpen, void (HWND hwnd)); // NOLINT - MOCK_METHOD1(OnWindowClose, void (HWND hwnd)); // NOLINT - - void WatchWindow(std::string caption_pattern) { - window_watcher_.AddObserver(this, caption_pattern); + // Override WindowObserver methods. + MOCK_METHOD2(OnWindowDetected, void (HWND hwnd, // NOLINT + const std::string& caption)); + + // Watch for all windows of the given class type. + void WatchWindow(const wchar_t* window_class) { + DCHECK(window_class); + window_watcher_.AddObserver(this, WideToUTF8(window_class)); } private: diff --git a/chrome_frame/test/navigation_test.cc b/chrome_frame/test/navigation_test.cc index 62cb876..0701a30 100644 --- a/chrome_frame/test/navigation_test.cc +++ b/chrome_frame/test/navigation_test.cc @@ -287,7 +287,6 @@ TEST_P(FullTabNavigationTest, FLAKY_RestrictedSite) { return; } MockWindowObserver win_observer_mock; - ScopedComPtr<IInternetSecurityManager> security_manager; HRESULT hr = security_manager.CreateInstance(CLSID_InternetSecurityManager); ASSERT_HRESULT_SUCCEEDED(hr); @@ -295,25 +294,25 @@ TEST_P(FullTabNavigationTest, FLAKY_RestrictedSite) { hr = security_manager->SetZoneMapping(URLZONE_UNTRUSTED, GetTestUrl(L"").c_str(), SZM_CREATE); - EXPECT_CALL(ie_mock_, OnFileDownload(_, _)).Times(testing::AnyNumber()); + EXPECT_CALL(ie_mock_, OnFileDownload(_, _)) + .Times(testing::AnyNumber()); server_mock_.ExpectAndServeAnyRequests(GetParam()); ProtocolPatchMethod patch_method = GetPatchMethod(); + const wchar_t* kDialogClass = L"#32770"; const char* kAlertDlgCaption = "Security Alert"; - EXPECT_CALL(ie_mock_, OnBeforeNavigate2( - _, - testing::Field(&VARIANT::bstrVal, testing::StrCaseEq(GetSimplePageUrl())), - _, _, _, _, _)) - .Times(1) - .WillOnce(WatchWindow(&win_observer_mock, kAlertDlgCaption)); + EXPECT_CALL(ie_mock_, OnBeforeNavigate2(_, + testing::Field(&VARIANT::bstrVal, + testing::StrCaseEq(GetSimplePageUrl())), _, _, _, _, _)) + .Times(1) + .WillOnce(WatchWindow(&win_observer_mock, kDialogClass)); if (patch_method == PATCH_METHOD_INET_PROTOCOL) { - EXPECT_CALL(ie_mock_, OnBeforeNavigate2( - _, - testing::Field(&VARIANT::bstrVal, testing::HasSubstr(L"res://")), - _, _, _, _, _)) + EXPECT_CALL(ie_mock_, OnBeforeNavigate2(_, + testing::Field(&VARIANT::bstrVal, + testing::HasSubstr(L"res://")), _, _, _, _, _)) .Times(testing::AtMost(1)); } @@ -321,12 +320,11 @@ TEST_P(FullTabNavigationTest, FLAKY_RestrictedSite) { testing::Field(&VARIANT::bstrVal, StrEq(GetSimplePageUrl())))) .Times(testing::AtMost(1)); - EXPECT_CALL(win_observer_mock, OnWindowOpen(_)) - .Times(1) - .WillOnce(DoCloseWindow()); - EXPECT_CALL(win_observer_mock, OnWindowClose(_)) + EXPECT_CALL(win_observer_mock, OnWindowDetected(_, StrEq(kAlertDlgCaption))) .Times(1) - .WillOnce(CloseBrowserMock(&ie_mock_)); + .WillOnce(testing::DoAll( + DoCloseWindow(), + CloseBrowserMock(&ie_mock_))); LaunchIEAndNavigate(GetSimplePageUrl()); diff --git a/chrome_frame/test/net/fake_external_tab.cc b/chrome_frame/test/net/fake_external_tab.cc index 59d4f84..b42b13b 100644 --- a/chrome_frame/test/net/fake_external_tab.cc +++ b/chrome_frame/test/net/fake_external_tab.cc @@ -105,8 +105,7 @@ class SupplyProxyCredentials : public WindowObserver { HWND password_; }; - virtual void OnWindowOpen(HWND hwnd); - virtual void OnWindowClose(HWND hwnd); + virtual void OnWindowDetected(HWND hwnd, const std::string& caption); static BOOL CALLBACK EnumChildren(HWND hwnd, LPARAM param); protected: @@ -120,9 +119,12 @@ SupplyProxyCredentials::SupplyProxyCredentials(const char* username, : username_(username), password_(password) { } -void SupplyProxyCredentials::OnWindowClose(HWND hwnd) { } +void SupplyProxyCredentials::OnWindowDetected(HWND hwnd, + const std::string& caption) { + // IE's dialog caption (en-US). + if (caption.compare("Windows Security") != 0) + return; -void SupplyProxyCredentials::OnWindowOpen(HWND hwnd) { DialogProps props = {0}; ::EnumChildWindows(hwnd, EnumChildren, reinterpret_cast<LPARAM>(&props)); DCHECK(::IsWindow(props.username_)); @@ -472,7 +474,8 @@ int main(int argc, char** argv) { WindowWatchdog watchdog; // See url_request_unittest.cc for these credentials. SupplyProxyCredentials credentials("user", "secret"); - watchdog.AddObserver(&credentials, "Windows Security"); + // Check for a dialog class ("#32770") + watchdog.AddObserver(&credentials, "#32770"); testing::InitGoogleTest(&argc, argv); FilterDisabledTests(); PluginService::EnableChromePlugins(false); diff --git a/chrome_frame/test/ui_test.cc b/chrome_frame/test/ui_test.cc index 6224d80..54fd0d2 100644 --- a/chrome_frame/test/ui_test.cc +++ b/chrome_frame/test/ui_test.cc @@ -112,23 +112,23 @@ TEST_P(FullTabUITest, FLAKY_CtrlN) { // events for New Window, but for Crl+N we don't get any // OnNewWindowX notifications. :( MockWindowObserver win_observer_mock; - - const char* kNewWindowTitlePattern = "*Internet Explorer*"; + const wchar_t* kIEFrameClass = L"IEFrame"; EXPECT_CALL(ie_mock_, OnLoad(is_cf, StrEq(GetSimplePageUrl()))) .WillOnce(testing::DoAll( - WatchWindow(&win_observer_mock, kNewWindowTitlePattern), + WatchWindow(&win_observer_mock, kIEFrameClass), SetFocusToRenderer(&ie_mock_), DelaySendChar(&loop_, 1000, 'n', simulate_input::CONTROL))); - // Watch for new window. It appears that the window close message cannot be - // reliably delivered immediately upon receipt of the window open event. - EXPECT_CALL(win_observer_mock, OnWindowOpen(_)) - .WillOnce(DelayDoCloseWindow(500)); - - EXPECT_CALL(win_observer_mock, OnWindowClose(_)) - .WillOnce(CloseBrowserMock(&ie_mock_)); + // Watch for new window + const char* kNewWindowTitle = "Internet Explorer"; + EXPECT_CALL(win_observer_mock, + OnWindowDetected(_, testing::HasSubstr(kNewWindowTitle))) + .WillOnce(testing::DoAll( + DoCloseWindow(), + CloseBrowserMock(&ie_mock_))); LaunchIEAndNavigate(GetSimplePageUrl()); + // TODO(kkania): The new window does not close properly sometimes. } // Test that ctrl+r does cause a refresh. @@ -389,20 +389,20 @@ TEST_F(ContextMenuTest, CFPageInfo) { InSequence expect_in_sequence_for_scope; // View page information. - const char* kPageInfoCaption = "Security Information"; + const wchar_t* kPageInfoWindowClass = L"Chrome_WidgetWin_0"; EXPECT_CALL(acc_observer_, OnAccDocLoad(_)) .WillOnce(testing::DoAll( - WatchWindow(&win_observer_mock, kPageInfoCaption), + WatchWindow(&win_observer_mock, kPageInfoWindowClass), OpenContextMenuAsync())); EXPECT_CALL(acc_observer_, OnMenuPopup(_)) .WillOnce(AccLeftClick(AccObjectMatcher(L"View page info"))); // Expect page info dialog to pop up. Dismiss the dialog with 'Esc' key - EXPECT_CALL(win_observer_mock, OnWindowOpen(_)) - .WillOnce(DoCloseWindow()); - - EXPECT_CALL(win_observer_mock, OnWindowClose(_)) - .WillOnce(CloseBrowserMock(&ie_mock_)); + const char* kPageInfoCaption = "Security Information"; + EXPECT_CALL(win_observer_mock, OnWindowDetected(_, StrEq(kPageInfoCaption))) + .WillOnce(testing::DoAll( + DoCloseWindow(), + CloseBrowserMock(&ie_mock_))); LaunchIEAndNavigate(GetSimplePageUrl()); } @@ -413,20 +413,22 @@ TEST_F(ContextMenuTest, CFInspector) { InSequence expect_in_sequence_for_scope; // Open developer tools. - // Devtools begins life with "Untitled" caption and it changes - // later to the 'Developer Tools - <url> form. - const char* kPageInfoCaptionPattern = "Untitled*"; + const wchar_t* kPageInfoWindowClass = L"Chrome_WidgetWin_0"; EXPECT_CALL(acc_observer_, OnAccDocLoad(_)) .WillOnce(testing::DoAll( - WatchWindow(&win_observer_mock, kPageInfoCaptionPattern), + WatchWindow(&win_observer_mock, kPageInfoWindowClass), OpenContextMenuAsync())); EXPECT_CALL(acc_observer_, OnMenuPopup(_)) .WillOnce(AccLeftClick(AccObjectMatcher(L"Inspect element"))); - EXPECT_CALL(win_observer_mock, OnWindowOpen(_)) - .WillOnce(DelayDoCloseWindow(5000)); // wait to catch possible crash - EXPECT_CALL(win_observer_mock, OnWindowClose(_)) - .WillOnce(CloseBrowserMock(&ie_mock_)); + // Devtools begins life with "Untitled" caption and it changes + // later to the 'Developer Tools - <url> form. + const char* kPageInfoCaption = "Untitled"; + EXPECT_CALL(win_observer_mock, + OnWindowDetected(_, testing::StartsWith(kPageInfoCaption))) + .WillOnce(testing::DoAll( + DelayDoCloseWindow(5000), // wait to catch possible crash + DelayCloseBrowserMock(&loop_, 5500, &ie_mock_))); LaunchIENavigateAndLoop(GetSimplePageUrl(), kChromeFrameLongNavigationTimeoutInSeconds * 2); @@ -435,14 +437,13 @@ TEST_F(ContextMenuTest, CFInspector) { TEST_F(ContextMenuTest, CFSaveAs) { server_mock_.ExpectAndServeAnyRequests(CFInvocation::MetaTag()); MockWindowObserver win_observer_mock; - InSequence expect_in_sequence_for_scope; // Open 'Save As' dialog. - const char* kSaveDlgCaption = "Save As"; + const wchar_t* kSaveDlgClass = L"#32770"; EXPECT_CALL(acc_observer_, OnAccDocLoad(_)) .WillOnce(testing::DoAll( - WatchWindow(&win_observer_mock, kSaveDlgCaption), + WatchWindow(&win_observer_mock, kSaveDlgClass), OpenContextMenuAsync())); EXPECT_CALL(acc_observer_, OnMenuPopup(_)) .WillOnce(AccLeftClick(AccObjectMatcher(L"Save as..."))); @@ -453,14 +454,12 @@ TEST_F(ContextMenuTest, CFSaveAs) { temp_file_path = temp_file_path.ReplaceExtension(L".htm"); ASSERT_TRUE(file_util::DieFileDie(temp_file_path, false)); - EXPECT_CALL(win_observer_mock, OnWindowOpen(_)) + EXPECT_CALL(win_observer_mock, OnWindowDetected(_, StrEq("Save As"))) .WillOnce(testing::DoAll( AccSetValue(AccObjectMatcher(L"File name:", L"", L"simple*"), - temp_file_path.value()), - AccDoDefaultAction(AccObjectMatcher(L"Save", L"push button")))); - - EXPECT_CALL(win_observer_mock, OnWindowClose(_)) - .WillOnce(CloseWhenFileSaved(&ie_mock_, temp_file_path, 5000)); + temp_file_path.value()), + AccDoDefaultAction(AccObjectMatcher(L"Save", L"push button")), + CloseWhenFileSaved(&ie_mock_, temp_file_path, 5000))); LaunchIENavigateAndLoop(GetSimplePageUrl(), kChromeFrameLongNavigationTimeoutInSeconds * 2); diff --git a/chrome_frame/test/win_event_receiver.cc b/chrome_frame/test/win_event_receiver.cc index c3ae0b3..e6295cd 100644 --- a/chrome_frame/test/win_event_receiver.cc +++ b/chrome_frame/test/win_event_receiver.cc @@ -5,8 +5,6 @@ #include "chrome_frame/test/win_event_receiver.h" #include "base/logging.h" -#include "base/message_loop.h" -#include "base/object_watcher.h" #include "base/string_util.h" #include "chrome_frame/function_stub.h" @@ -70,93 +68,18 @@ void WinEventReceiver::WinEventHook(WinEventReceiver* me, HWINEVENTHOOK hook, me->listener_->OnEventReceived(event, hwnd, object_id, child_id); } -// Notifies WindowWatchdog when the process owning a given window exits. -// -// If the process terminates before its handle may be obtained, this class will -// still properly notifyy the WindowWatchdog. -// -// Notification is always delivered via a message loop task in the message loop -// that is active when the instance is constructed. -class WindowWatchdog::ProcessExitObserver - : public base::ObjectWatcher::Delegate { - public: - // Initiates the process watch. Will always return without notifying the - // watchdog. - ProcessExitObserver(WindowWatchdog* window_watchdog, HWND hwnd); - virtual ~ProcessExitObserver(); - - // base::ObjectWatcher::Delegate implementation - virtual void OnObjectSignaled(HANDLE process_handle); - - private: - WindowWatchdog* window_watchdog_; - HANDLE process_handle_; - HWND hwnd_; - - ScopedRunnableMethodFactory<ProcessExitObserver> method_task_factory_; - base::ObjectWatcher object_watcher_; - - DISALLOW_COPY_AND_ASSIGN(ProcessExitObserver); -}; - -WindowWatchdog::ProcessExitObserver::ProcessExitObserver( - WindowWatchdog* window_watchdog, HWND hwnd) - : window_watchdog_(window_watchdog), - process_handle_(NULL), - hwnd_(hwnd), - ALLOW_THIS_IN_INITIALIZER_LIST(method_task_factory_(this)) { - DWORD pid = 0; - ::GetWindowThreadProcessId(hwnd, &pid); - if (pid != 0) { - process_handle_ = ::OpenProcess(SYNCHRONIZE, FALSE, pid); - } - - if (process_handle_ != NULL) { - object_watcher_.StartWatching(process_handle_, this); - } else { - // Process is gone, so the window must be gone too. Notify our observer! - MessageLoop::current()->PostTask( - FROM_HERE, - method_task_factory_.NewRunnableMethod( - &ProcessExitObserver::OnObjectSignaled, HANDLE(NULL))); - } -} - -WindowWatchdog::ProcessExitObserver::~ProcessExitObserver() { - if (process_handle_ != NULL) { - ::CloseHandle(process_handle_); - } -} - -void WindowWatchdog::ProcessExitObserver::OnObjectSignaled( - HANDLE process_handle) { - window_watchdog_->OnHwndProcessExited(hwnd_); -} - -WindowWatchdog::WindowWatchdog() {} - +// WindowWatchdog methods void WindowWatchdog::AddObserver(WindowObserver* observer, - const std::string& caption_pattern) { - if (observers_.empty()) { - // SetListenerForEvents takes an event_min and event_max. - // EVENT_OBJECT_DESTROY, EVENT_OBJECT_SHOW, and EVENT_OBJECT_HIDE are - // consecutive, in that order; hence we supply only DESTROY and HIDE to - // denote exactly the required set. - win_event_receiver_.SetListenerForEvents( - this, EVENT_OBJECT_DESTROY, EVENT_OBJECT_HIDE); - } - - ObserverEntry new_entry = { - observer, - caption_pattern, - OpenWindowList() }; + const std::string& window_class) { + if (observers_.empty()) + win_event_receiver_.SetListenerForEvent(this, EVENT_OBJECT_SHOW); + WindowObserverEntry new_entry = { observer, window_class }; observers_.push_back(new_entry); } void WindowWatchdog::RemoveObserver(WindowObserver* observer) { - for (ObserverEntryList::iterator i = observers_.begin(); - i != observers_.end(); ) { + for (ObserverMap::iterator i = observers_.begin(); i != observers_.end();) { i = (observer == i->observer) ? observers_.erase(i) : ++i; } @@ -164,93 +87,31 @@ void WindowWatchdog::RemoveObserver(WindowObserver* observer) { win_event_receiver_.StopReceivingEvents(); } -std::string WindowWatchdog::GetWindowCaption(HWND hwnd) { - std::string caption; - int len = ::GetWindowTextLength(hwnd) + 1; - ::GetWindowTextA(hwnd, WriteInto(&caption, len), len); - - return caption; -} - -void WindowWatchdog::HandleOnOpen(HWND hwnd) { - std::string caption = GetWindowCaption(hwnd); - - // Instantiated only if there is at least one interested observer. Each - // interested observer will maintain a reference to this object, such that it - // is deleted when the last observer disappears. - linked_ptr<ProcessExitObserver> process_exit_observer; - - // Identify the interested observers and mark them as watching this HWND for - // close. - ObserverEntryList interested_observers; - for (ObserverEntryList::iterator entry_iter = observers_.begin(); - entry_iter != observers_.end(); ++entry_iter) { - if (MatchPattern(caption, entry_iter->caption_pattern)) { - if (process_exit_observer == NULL) { - process_exit_observer.reset(new ProcessExitObserver(this, hwnd)); - } - - entry_iter->open_windows.push_back( - OpenWindowEntry(hwnd, process_exit_observer)); - - interested_observers.push_back(*entry_iter); - } - } - - // Notify the interested observers in a separate pass in case AddObserver or - // RemoveObserver is called as a side-effect of the notification. - for (ObserverEntryList::iterator entry_iter = interested_observers.begin(); - entry_iter != interested_observers.end(); ++entry_iter) { - entry_iter->observer->OnWindowOpen(hwnd); - } -} - -void WindowWatchdog::HandleOnClose(HWND hwnd) { - // Identify the interested observers, reaping OpenWindow entries as - // appropriate - ObserverEntryList interested_observers; - for (ObserverEntryList::iterator entry_iter = observers_.begin(); - entry_iter != observers_.end(); ++entry_iter) { - size_t num_open_windows = entry_iter->open_windows.size(); +void WindowWatchdog::OnEventReceived(DWORD event, HWND hwnd, LONG object_id, + LONG child_id) { + // 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; - OpenWindowList::iterator window_iter = entry_iter->open_windows.begin(); - while (window_iter != entry_iter->open_windows.end()) { - if (hwnd == window_iter->first) { - window_iter = entry_iter->open_windows.erase(window_iter); - } else { - ++window_iter; - } - } + char class_name[MAX_PATH] = {0}; + ::GetClassNameA(hwnd, class_name, arraysize(class_name)); - if (num_open_windows != entry_iter->open_windows.size()) { - interested_observers.push_back(*entry_iter); + ObserverMap interested_observers; + for (ObserverMap::iterator i = observers_.begin(); + i != observers_.end(); i++) { + if (0 == lstrcmpA(i->window_class.c_str(), class_name)) { + interested_observers.push_back(*i); } } - // Notify the interested observers in a separate pass in case AddObserver or - // RemoveObserver is called as a side-effect of the notification. - for (ObserverEntryList::iterator entry_iter = interested_observers.begin(); - entry_iter != interested_observers.end(); ++entry_iter) { - entry_iter->observer->OnWindowClose(hwnd); - } -} + std::string caption; + int len = ::GetWindowTextLength(hwnd) + 1; + ::GetWindowTextA(hwnd, WriteInto(&caption, len), len); -void WindowWatchdog::OnEventReceived( - DWORD event, HWND hwnd, LONG object_id, LONG child_id) { - // 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; + for (ObserverMap::iterator i = interested_observers.begin(); + i != interested_observers.end(); i++) { + i->observer->OnWindowDetected(hwnd, caption); } - if (event == EVENT_OBJECT_SHOW) { - HandleOnOpen(hwnd); - } else { - DCHECK(event == EVENT_OBJECT_DESTROY || event == EVENT_OBJECT_HIDE); - HandleOnClose(hwnd); - } -} - -void WindowWatchdog::OnHwndProcessExited(HWND hwnd) { - HandleOnClose(hwnd); } diff --git a/chrome_frame/test/win_event_receiver.h b/chrome_frame/test/win_event_receiver.h index d91f268..c330520 100644 --- a/chrome_frame/test/win_event_receiver.h +++ b/chrome_frame/test/win_event_receiver.h @@ -9,10 +9,6 @@ #include <string> #include <vector> -#include <utility> - -#include "base/linked_ptr.h" -#include "base/object_watcher.h" struct FunctionStub; @@ -58,79 +54,39 @@ class WinEventReceiver { FunctionStub* hook_stub_; }; -// Receives notifications when a window is opened or closed. +// Observes window show events. Used with WindowWatchdog. class WindowObserver { public: virtual ~WindowObserver() {} - virtual void OnWindowOpen(HWND hwnd) = 0; - virtual void OnWindowClose(HWND hwnd) = 0; + // Called when a window has been shown. + virtual void OnWindowDetected(HWND hwnd, const std::string& caption) = 0; }; -// Notifies observers when windows whose captions match specified patterns -// open or close. When a window opens, its caption is compared to the patterns -// associated with each observer. Observers registered with matching patterns -// are notified of the window's opening and will be notified when the same -// window is closed (including if the owning process terminates without closing -// the window). -// -// Changes to a window's caption while it is open do not affect the set of -// observers to be notified when it closes. -// -// Observers are not notified of the closing of windows that were already open -// when they were registered. -// -// Observers may call AddObserver and/or RemoveObserver during notifications. -// -// Each instance of this class must only be accessed from a single thread, and -// that thread must be running a message loop. +// Watch a for window to be shown with the given window class name. +// If found, call the observer interested in it. class WindowWatchdog : public WinEventListener { public: - WindowWatchdog(); - // Register |observer| to be notified when windows matching |caption_pattern| - // are opened or closed. A single observer may be registered multiple times. - // If a single window caption matches multiple registrations of a single - // observer, the observer will be notified once per matching registration. - void AddObserver(WindowObserver* observer, - const std::string& caption_pattern); - - // Remove all registrations of |observer|. The |observer| will not be notified - // during or after this call. + // 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); private: - class ProcessExitObserver; - - // The Delegate object is actually a ProcessExitObserver, but declaring - // it as such would require fully declaring the ProcessExitObserver class - // here in order for linked_ptr to access its destructor. - typedef std::pair<HWND, linked_ptr<base::ObjectWatcher::Delegate> > - OpenWindowEntry; - typedef std::vector<OpenWindowEntry> OpenWindowList; - - struct ObserverEntry { + struct WindowObserverEntry { WindowObserver* observer; - std::string caption_pattern; - OpenWindowList open_windows; + std::string window_class; }; - typedef std::vector<ObserverEntry> ObserverEntryList; - - // WinEventListener implementation. - virtual void OnEventReceived( - DWORD event, HWND hwnd, LONG object_id, LONG child_id); + typedef std::vector<WindowObserverEntry> ObserverMap; - static std::string GetWindowCaption(HWND hwnd); - - void HandleOnOpen(HWND hwnd); - void HandleOnClose(HWND hwnd); - void OnHwndProcessExited(HWND hwnd); + // Overriden from WinEventListener. + virtual void OnEventReceived(DWORD event, HWND hwnd, LONG object_id, + LONG child_id); - ObserverEntryList observers_; + ObserverMap observers_; WinEventReceiver win_event_receiver_; - - DISALLOW_COPY_AND_ASSIGN(WindowWatchdog); }; - - #endif // CHROME_FRAME_TEST_WIN_EVENT_RECEIVER_H_ |