1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #ifndef CHROME_FRAME_TEST_MOCK_IE_EVENT_SINK_ACTIONS_H_
6 #define CHROME_FRAME_TEST_MOCK_IE_EVENT_SINK_ACTIONS_H_
12 #include "base/basictypes.h"
13 #include "base/bind.h"
14 #include "base/strings/string16.h"
15 #include "base/strings/string_util.h"
16 #include "base/test/test_process_killer_win.h"
17 #include "base/threading/platform_thread.h"
18 #include "base/time/time.h"
19 #include "chrome/common/chrome_switches.h"
20 #include "chrome_frame/test/chrome_frame_test_utils.h"
21 #include "chrome_frame/test/ie_event_sink.h"
22 #include "chrome_frame/test/mock_ie_event_sink_test.h"
23 #include "chrome_frame/test/simulate_input.h"
24 #include "testing/gmock/include/gmock/gmock.h"
25 #include "ui/gfx/point.h"
26 #include "ui/gfx/rect.h"
28 namespace chrome_frame_test {
30 MATCHER_P(UrlPathEq, url, "equals the path and query portion of the url") {
31 return arg == chrome_frame_test::GetPathAndQueryFromUrl(url);
34 MATCHER_P(AccSatisfies, matcher, "satisfies the given AccObjectMatcher") {
35 return matcher.DoesMatch(arg);
38 // Returns true if the title of the page rendered in the window |arg| equals
39 // |the_url| or |the_title|. For pages rendered in Chrome, the title of the
40 // parent of |arg| is the page url or title. For pages rendered in IE, the title
41 // of the grandparent of |arg| begins with the page url or title. To handle both
42 // cases, attempt a prefix match on each window starting with the parent of
43 // |arg|. Both url and title are matched to account for a race between the test
44 // and Chrome when the window title is transitioned from the url to the title.
45 MATCHER_P2(TabContentsTitleEq, the_url, the_title, "") {
46 const string16 url(the_url);
48 const string16 title(the_title);
49 DCHECK(!title.empty());
50 HWND parent = GetParent(arg);
52 string16 parent_title(255, L'\0');
53 std::ostringstream titles_found(std::string("titles found: "));
56 parent_title.resize(255, L'\0');
57 parent_title.resize(GetWindowText(parent, &parent_title[0],
58 parent_title.size()));
59 if (parent_title.size() >= title.size() &&
60 std::equal(title.begin(), title.end(), parent_title.begin()) ||
61 parent_title.size() >= url.size() &&
62 std::equal(url.begin(), url.end(), parent_title.begin())) {
65 titles_found << "\"" << UTF16ToASCII(parent_title) << "\" ";
66 parent = GetParent(parent);
67 } while(parent != NULL);
68 *result_listener << titles_found.str();
70 *result_listener << "the window has no parent";
75 // IWebBrowser2 actions
77 ACTION_P2(Navigate, mock, navigate_url) {
78 mock->event_sink()->Navigate(navigate_url);
81 ACTION_P3(DelayNavigateToCurrentUrl, mock, loop, delay) {
82 loop->PostDelayedTask(FROM_HERE,
83 base::Bind(&NavigateToCurrentUrl, mock), delay);
86 ACTION_P(CloseBrowserMock, mock) {
87 mock->event_sink()->CloseWebBrowser();
90 ACTION_P3(DelayCloseBrowserMock, loop, delay, mock) {
91 loop->PostDelayedTask(
93 base::Bind(base::IgnoreResult(&IEEventSink::CloseWebBrowser),
98 ACTION_P2(ConnectDocPropNotifySink, mock, sink) {
99 base::win::ScopedComPtr<IDispatch> document;
100 mock->event_sink()->web_browser2()->get_Document(document.Receive());
101 EXPECT_TRUE(document != NULL); // NOLINT
103 sink->Attach(document);
107 ACTION_P(DisconnectDocPropNotifySink, sink) {
111 ACTION_P8(DelayExecCommand, mock, loop, delay, cmd_group_guid, cmd_id,
112 cmd_exec_opt, in_args, out_args) {
113 loop->PostDelayedTask(
115 base::Bind(&IEEventSink::Exec, mock->event_sink(), cmd_group_guid, cmd_id,
116 cmd_exec_opt, in_args, out_args),
120 ACTION_P3(DelayGoBack, mock, loop, delay) {
121 loop->PostDelayedTask(
122 FROM_HERE, base::Bind(&IEEventSink::GoBack, mock->event_sink()), delay);
125 ACTION_P3(DelayGoForward, mock, loop, delay) {
126 loop->PostDelayedTask(
127 FROM_HERE, base::Bind(&IEEventSink::GoForward, mock->event_sink()),
131 ACTION_P3(DelayRefresh, mock, loop, delay) {
132 loop->PostDelayedTask(
133 FROM_HERE, base::Bind(&IEEventSink::Refresh, mock->event_sink()), delay);
136 ACTION_P2(PostMessageToCF, mock, message) {
137 mock->event_sink()->PostMessageToCF(message, L"*");
140 // Accessibility-related actions
142 ACTION_P(AccDoDefaultAction, matcher) {
143 scoped_refptr<AccObject> object;
144 if (FindAccObjectInWindow(arg0, matcher, &object)) {
145 EXPECT_TRUE(object->DoDefaultAction());
149 ACTION_P2(DelayAccDoDefaultAction, matcher, delay) {
150 SleepEx(delay, false);
151 scoped_refptr<AccObject> object;
152 if (FindAccObjectInWindow(arg0, matcher, &object)) {
153 EXPECT_TRUE(object->DoDefaultAction());
157 ACTION_P(AccLeftClick, matcher) {
158 scoped_refptr<AccObject> object;
159 if (FindAccObjectInWindow(arg0, matcher, &object)) {
160 EXPECT_TRUE(object->LeftClick());
164 ACTION_P(AccSendCommand, matcher) {
165 scoped_refptr<AccObject> object;
166 if (FindAccObjectInWindow(arg0, matcher, &object)) {
168 object->GetWindow(&window);
169 long window_id = GetWindowLong(window, GWL_ID);
170 ::SendMessage(arg0, WM_COMMAND, MAKEWPARAM(window_id, BN_CLICKED),
171 reinterpret_cast<LPARAM>(window));
175 ACTION_P(AccRightClick, matcher) {
176 scoped_refptr<AccObject> object;
177 if (FindAccObjectInWindow(arg0, matcher, &object)) {
178 EXPECT_TRUE(object->RightClick());
182 ACTION_P(AccFocus, matcher) {
183 scoped_refptr<AccObject> object;
184 if (FindAccObjectInWindow(arg0, matcher, &object)) {
185 EXPECT_TRUE(object->Focus());
189 ACTION_P(AccSelect, matcher) {
190 scoped_refptr<AccObject> object;
191 if (FindAccObjectInWindow(arg0, matcher, &object)) {
192 EXPECT_TRUE(object->Select());
196 ACTION_P2(AccSetValue, matcher, value) {
197 scoped_refptr<AccObject> object;
198 if (FindAccObjectInWindow(arg0, matcher, &object)) {
199 EXPECT_TRUE(object->SetValue(value));
203 namespace { // NOLINT
204 template<typename R> R AccInWindow(testing::Action<R(HWND)> action, HWND hwnd) {
205 return action.Perform(typename testing::Action<R(HWND)>::ArgumentTuple(hwnd));
209 ACTION_P2(AccDoDefaultActionInBrowser, mock, matcher) {
210 AccInWindow<void>(AccDoDefaultAction(matcher),
211 mock->event_sink()->GetBrowserWindow());
214 ACTION_P2(AccDoDefaultActionInRenderer, mock, matcher) {
215 AccInWindow<void>(AccDoDefaultAction(matcher),
216 mock->event_sink()->GetRendererWindow());
219 ACTION_P3(DelayAccDoDefaultActionInRenderer, mock, matcher, delay) {
220 SleepEx(delay, false);
221 AccInWindow<void>(AccDoDefaultAction(matcher),
222 mock->event_sink()->GetRendererWindow());
225 ACTION_P2(AccLeftClickInBrowser, mock, matcher) {
226 AccInWindow<void>(AccLeftClick(matcher),
227 mock->event_sink()->GetBrowserWindow());
230 ACTION_P2(AccLeftClickInRenderer, mock, matcher) {
231 AccInWindow<void>(AccLeftClick(matcher),
232 mock->event_sink()->GetRendererWindow());
235 ACTION_P3(AccSetValueInBrowser, mock, matcher, value) {
236 AccInWindow<void>(AccSetValue(matcher, value),
237 mock->event_sink()->GetBrowserWindow());
240 ACTION_P2(AccWatchForOneValueChange, observer, matcher) {
241 observer->WatchForOneValueChange(matcher);
244 ACTION_P2(AccSendCharMessage, matcher, character_code) {
245 scoped_refptr<AccObject> object;
246 if (FindAccObjectInWindow(arg0, matcher, &object)) {
248 EXPECT_TRUE(object->GetWindow(&window));
249 ::SendMessage(window, WM_CHAR, character_code, 0);
253 // Various other actions
255 ACTION(OpenContextMenuAsync) {
256 // Special case this implementation because the top-left of the window is
257 // much more likely to be empty than the center.
259 LPARAM coordinates = (1 << 16) | 1;
260 // IE needs both messages in order to work. Chrome does not support
261 // WM_CONTEXTMENU in the renderer: http://crbug.com/51746.
262 ::PostMessage(hwnd, WM_RBUTTONDOWN, 0, coordinates);
263 ::PostMessage(hwnd, WM_RBUTTONUP, 0, coordinates);
266 // Posts a WM_KEYDOWN and WM_KEYUP message to the renderer window. Modifiers are
267 // not supported, so |character_code| is limited to the regular expression
269 ACTION_P2(PostKeyMessageToRenderer, mock, character_code) {
270 char character_codes[] = { character_code, '\0' };
271 mock->event_sink()->SendKeys(character_codes);
274 // Posts WM_KEYDOWN and WM_KEYUP messages to the renderer window. Modifiers are
275 // not supported, so |character_codes| is limited to the regular expression
277 ACTION_P2(PostKeyMessagesToRenderer, mock, character_codes) {
278 mock->event_sink()->SendKeys(std::string(character_codes).c_str());
281 ACTION_P3(WatchWindow, mock, caption, window_class) {
282 mock->WatchWindow(caption, window_class);
285 ACTION_P(StopWindowWatching, mock) {
286 mock->StopWatching();
289 ACTION_P(WatchWindowProcess, mock_observer) {
290 mock_observer->WatchProcessForHwnd(arg0);
293 ACTION_P2(WatchBrowserProcess, mock_observer, mock) {
294 AccInWindow<void>(WatchWindowProcess(mock_observer),
295 mock->event_sink()->GetBrowserWindow());
298 ACTION_P2(WatchRendererProcess, mock_observer, mock) {
299 AccInWindow<void>(WatchWindowProcess(mock_observer),
300 mock->event_sink()->GetRendererWindow());
303 namespace { // NOLINT
305 void DoCloseWindowNow(HWND hwnd) {
306 ::PostMessage(hwnd, WM_CLOSE, 0, 0);
311 ACTION(DoCloseWindow) {
312 DoCloseWindowNow(arg0);
315 ACTION_P(DelayDoCloseWindow, delay) {
316 DCHECK(base::MessageLoop::current());
317 base::MessageLoop::current()->PostDelayedTask(
318 FROM_HERE, base::Bind(DoCloseWindowNow, arg0),
319 base::TimeDelta::FromMilliseconds(delay));
322 ACTION(KillChromeFrameProcesses) {
323 base::KillAllNamedProcessesWithArgument(
324 UTF8ToWide(chrome_frame_test::kChromeImageName),
325 UTF8ToWide(switches::kChromeFrame));
329 ACTION_P(AccExpect, matcher) {
330 scoped_refptr<AccObject> object;
331 EXPECT_TRUE(FindAccObjectInWindow(arg0, matcher, &object));
334 ACTION_P2(AccExpectInRenderer, mock, matcher) {
335 AccInWindow<void>(AccExpect(matcher),
336 mock->event_sink()->GetRendererWindow());
339 ACTION_P(ExpectRendererHasFocus, mock) {
340 mock->event_sink()->ExpectRendererWindowHasFocus();
343 ACTION_P(VerifyAddressBarUrl, mock) {
344 mock->event_sink()->ExpectAddressBarUrl(std::wstring(arg1));
347 ACTION_P3(VerifyPageLoad, mock, in_cf, url) {
348 EXPECT_TRUE(static_cast<bool>(in_cf) == mock->event_sink()->IsCFRendering());
349 mock->event_sink()->ExpectAddressBarUrl(url);
352 ACTION_P5(ValidateWindowSize, mock, left, top, width, height) {
355 int actual_width = 0;
356 int actual_height = 0;
358 IWebBrowser2* web_browser2 = mock->event_sink()->web_browser2();
359 web_browser2->get_Left(reinterpret_cast<long*>(&actual_left)); // NOLINT
360 web_browser2->get_Top(reinterpret_cast<long*>(&actual_top)); // NOLINT
361 web_browser2->get_Width(reinterpret_cast<long*>(&actual_width)); // NOLINT
362 web_browser2->get_Height(reinterpret_cast<long*>(&actual_height)); // NOLINT
364 EXPECT_GE(actual_left, left);
365 EXPECT_GE(actual_top, top);
367 EXPECT_GE(actual_width, width);
368 EXPECT_GE(actual_height, height);
371 ACTION_P(VerifyAddressBarUrlWithGcf, mock) {
372 std::wstring expected_url = L"gcf:";
373 expected_url += arg1;
374 mock->event_sink()->ExpectAddressBarUrl(expected_url);
377 ACTION_P2(ExpectDocumentReadystate, mock, ready_state) {
378 mock->ExpectDocumentReadystate(ready_state);
381 ACTION_P(VerifySelectedText, expected_text) {
382 std::wstring actual_text;
383 bool got_selection = arg1->GetSelectedText(&actual_text);
384 EXPECT_TRUE(got_selection);
386 EXPECT_EQ(expected_text, actual_text);
392 ACTION_P3(CloseWhenFileSaved, mock, file, timeout_ms) {
393 base::Time start = base::Time::Now();
394 while (!base::PathExists(file)) {
395 if ((base::Time::Now() - start).InMilliseconds() > timeout_ms) {
396 ADD_FAILURE() << "File was not saved within timeout";
397 TakeSnapshotAndLog();
400 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(200));
402 mock->event_sink()->CloseWebBrowser();
405 ACTION_P2(WaitForFileSave, file, timeout_ms) {
406 base::Time start = base::Time::Now();
407 while (!base::PathExists(file)) {
408 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(200));
409 if ((base::Time::Now() - start).InMilliseconds() > timeout_ms) {
410 ADD_FAILURE() << "File was not saved within timeout";
411 TakeSnapshotAndLog();
419 ACTION_P(SetFocusToRenderer, mock) {
420 simulate_input::SetKeyboardFocusToWindow(
421 mock->event_sink()->GetRendererWindow());
424 ACTION_P4(DelaySendChar, loop, delay, c, mod) {
425 loop->PostDelayedTask(
426 FROM_HERE, base::Bind(simulate_input::SendCharA, c, mod), delay);
429 ACTION_P4(DelaySendScanCode, loop, delay, c, mod) {
430 loop->PostDelayedTask(
431 FROM_HERE, base::Bind(simulate_input::SendScanCode, c, mod), delay);
434 // This function selects the address bar via the Alt+d shortcut.
435 ACTION_P3(TypeUrlInAddressBar, loop, url, delay) {
436 loop->PostDelayedTask(
438 base::Bind(simulate_input::SendCharA, 'd', simulate_input::ALT), delay);
440 const base::TimeDelta kInterval = base::TimeDelta::FromMilliseconds(500);
441 base::TimeDelta next_delay = delay + kInterval;
443 loop->PostDelayedTask(
444 FROM_HERE, base::Bind(simulate_input::SendStringW, url), next_delay);
446 next_delay = next_delay + kInterval;
448 loop->PostDelayedTask(
450 base::Bind(simulate_input::SendCharA, VK_RETURN, simulate_input::NONE),
454 } // namespace chrome_frame_test
456 #endif // CHROME_FRAME_TEST_MOCK_IE_EVENT_SINK_ACTIONS_H_