- add sources.
[platform/framework/web/crosswalk.git] / src / chrome_frame / test / mock_ie_event_sink_actions.h
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.
4
5 #ifndef CHROME_FRAME_TEST_MOCK_IE_EVENT_SINK_ACTIONS_H_
6 #define CHROME_FRAME_TEST_MOCK_IE_EVENT_SINK_ACTIONS_H_
7
8 #include <windows.h>
9 #include <algorithm>
10 #include <string>
11
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"
27
28 namespace chrome_frame_test {
29
30 MATCHER_P(UrlPathEq, url, "equals the path and query portion of the url") {
31   return arg == chrome_frame_test::GetPathAndQueryFromUrl(url);
32 }
33
34 MATCHER_P(AccSatisfies, matcher, "satisfies the given AccObjectMatcher") {
35   return matcher.DoesMatch(arg);
36 }
37
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);
47   DCHECK(!url.empty());
48   const string16 title(the_title);
49   DCHECK(!title.empty());
50   HWND parent = GetParent(arg);
51   if (parent != NULL) {
52     string16 parent_title(255, L'\0');
53     std::ostringstream titles_found(std::string("titles found: "));
54     string16 first_title;
55     do {
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())) {
63         return true;
64       }
65       titles_found << "\"" << UTF16ToASCII(parent_title) << "\" ";
66       parent = GetParent(parent);
67     } while(parent != NULL);
68     *result_listener << titles_found.str();
69   } else {
70     *result_listener << "the window has no parent";
71   }
72   return false;
73 }
74
75 // IWebBrowser2 actions
76
77 ACTION_P2(Navigate, mock, navigate_url) {
78   mock->event_sink()->Navigate(navigate_url);
79 }
80
81 ACTION_P3(DelayNavigateToCurrentUrl, mock, loop, delay) {
82   loop->PostDelayedTask(FROM_HERE,
83                         base::Bind(&NavigateToCurrentUrl, mock), delay);
84 }
85
86 ACTION_P(CloseBrowserMock, mock) {
87   mock->event_sink()->CloseWebBrowser();
88 }
89
90 ACTION_P3(DelayCloseBrowserMock, loop, delay, mock) {
91   loop->PostDelayedTask(
92       FROM_HERE,
93       base::Bind(base::IgnoreResult(&IEEventSink::CloseWebBrowser),
94                  mock->event_sink()),
95       delay);
96 }
97
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
102   if (document) {
103     sink->Attach(document);
104   }
105 }
106
107 ACTION_P(DisconnectDocPropNotifySink, sink) {
108   sink->Detach();
109 }
110
111 ACTION_P8(DelayExecCommand, mock, loop, delay, cmd_group_guid, cmd_id,
112           cmd_exec_opt, in_args, out_args) {
113   loop->PostDelayedTask(
114       FROM_HERE,
115       base::Bind(&IEEventSink::Exec, mock->event_sink(), cmd_group_guid, cmd_id,
116                  cmd_exec_opt, in_args, out_args),
117       delay);
118 }
119
120 ACTION_P3(DelayGoBack, mock, loop, delay) {
121   loop->PostDelayedTask(
122       FROM_HERE, base::Bind(&IEEventSink::GoBack, mock->event_sink()), delay);
123 }
124
125 ACTION_P3(DelayGoForward, mock, loop, delay) {
126   loop->PostDelayedTask(
127       FROM_HERE, base::Bind(&IEEventSink::GoForward, mock->event_sink()),
128       delay);
129 }
130
131 ACTION_P3(DelayRefresh, mock, loop, delay) {
132   loop->PostDelayedTask(
133       FROM_HERE, base::Bind(&IEEventSink::Refresh, mock->event_sink()), delay);
134 }
135
136 ACTION_P2(PostMessageToCF, mock, message) {
137   mock->event_sink()->PostMessageToCF(message, L"*");
138 }
139
140 // Accessibility-related actions
141
142 ACTION_P(AccDoDefaultAction, matcher) {
143   scoped_refptr<AccObject> object;
144   if (FindAccObjectInWindow(arg0, matcher, &object)) {
145     EXPECT_TRUE(object->DoDefaultAction());
146   }
147 }
148
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());
154   }
155 }
156
157 ACTION_P(AccLeftClick, matcher) {
158   scoped_refptr<AccObject> object;
159   if (FindAccObjectInWindow(arg0, matcher, &object)) {
160     EXPECT_TRUE(object->LeftClick());
161   }
162 }
163
164 ACTION_P(AccSendCommand, matcher) {
165   scoped_refptr<AccObject> object;
166   if (FindAccObjectInWindow(arg0, matcher, &object)) {
167     HWND window = NULL;
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));
172   }
173 }
174
175 ACTION_P(AccRightClick, matcher) {
176   scoped_refptr<AccObject> object;
177   if (FindAccObjectInWindow(arg0, matcher, &object)) {
178     EXPECT_TRUE(object->RightClick());
179   }
180 }
181
182 ACTION_P(AccFocus, matcher) {
183   scoped_refptr<AccObject> object;
184   if (FindAccObjectInWindow(arg0, matcher, &object)) {
185     EXPECT_TRUE(object->Focus());
186   }
187 }
188
189 ACTION_P(AccSelect, matcher) {
190   scoped_refptr<AccObject> object;
191   if (FindAccObjectInWindow(arg0, matcher, &object)) {
192     EXPECT_TRUE(object->Select());
193   }
194 }
195
196 ACTION_P2(AccSetValue, matcher, value) {
197   scoped_refptr<AccObject> object;
198   if (FindAccObjectInWindow(arg0, matcher, &object)) {
199     EXPECT_TRUE(object->SetValue(value));
200   }
201 }
202
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));
206 }
207 }
208
209 ACTION_P2(AccDoDefaultActionInBrowser, mock, matcher) {
210   AccInWindow<void>(AccDoDefaultAction(matcher),
211                     mock->event_sink()->GetBrowserWindow());
212 }
213
214 ACTION_P2(AccDoDefaultActionInRenderer, mock, matcher) {
215   AccInWindow<void>(AccDoDefaultAction(matcher),
216                     mock->event_sink()->GetRendererWindow());
217 }
218
219 ACTION_P3(DelayAccDoDefaultActionInRenderer, mock, matcher, delay) {
220   SleepEx(delay, false);
221   AccInWindow<void>(AccDoDefaultAction(matcher),
222                     mock->event_sink()->GetRendererWindow());
223 }
224
225 ACTION_P2(AccLeftClickInBrowser, mock, matcher) {
226   AccInWindow<void>(AccLeftClick(matcher),
227                     mock->event_sink()->GetBrowserWindow());
228 }
229
230 ACTION_P2(AccLeftClickInRenderer, mock, matcher) {
231   AccInWindow<void>(AccLeftClick(matcher),
232                     mock->event_sink()->GetRendererWindow());
233 }
234
235 ACTION_P3(AccSetValueInBrowser, mock, matcher, value) {
236   AccInWindow<void>(AccSetValue(matcher, value),
237                     mock->event_sink()->GetBrowserWindow());
238 }
239
240 ACTION_P2(AccWatchForOneValueChange, observer, matcher) {
241   observer->WatchForOneValueChange(matcher);
242 }
243
244 ACTION_P2(AccSendCharMessage, matcher, character_code) {
245   scoped_refptr<AccObject> object;
246   if (FindAccObjectInWindow(arg0, matcher, &object)) {
247     HWND window = NULL;
248     EXPECT_TRUE(object->GetWindow(&window));
249     ::SendMessage(window, WM_CHAR, character_code, 0);
250   }
251 }
252
253 // Various other actions
254
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.
258   HWND hwnd = arg0;
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);
264 }
265
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
268 // [0-9a-z].
269 ACTION_P2(PostKeyMessageToRenderer, mock, character_code) {
270   char character_codes[] = { character_code, '\0' };
271   mock->event_sink()->SendKeys(character_codes);
272 }
273
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
276 // [0-9a-z]*.
277 ACTION_P2(PostKeyMessagesToRenderer, mock, character_codes) {
278   mock->event_sink()->SendKeys(std::string(character_codes).c_str());
279 }
280
281 ACTION_P3(WatchWindow, mock, caption, window_class) {
282   mock->WatchWindow(caption, window_class);
283 }
284
285 ACTION_P(StopWindowWatching, mock) {
286   mock->StopWatching();
287 }
288
289 ACTION_P(WatchWindowProcess, mock_observer) {
290   mock_observer->WatchProcessForHwnd(arg0);
291 }
292
293 ACTION_P2(WatchBrowserProcess, mock_observer, mock) {
294   AccInWindow<void>(WatchWindowProcess(mock_observer),
295                     mock->event_sink()->GetBrowserWindow());
296 }
297
298 ACTION_P2(WatchRendererProcess, mock_observer, mock) {
299   AccInWindow<void>(WatchWindowProcess(mock_observer),
300                     mock->event_sink()->GetRendererWindow());
301 }
302
303 namespace { // NOLINT
304
305 void DoCloseWindowNow(HWND hwnd) {
306   ::PostMessage(hwnd, WM_CLOSE, 0, 0);
307 }
308
309 }  // namespace
310
311 ACTION(DoCloseWindow) {
312   DoCloseWindowNow(arg0);
313 }
314
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));
320 }
321
322 ACTION(KillChromeFrameProcesses) {
323   base::KillAllNamedProcessesWithArgument(
324       UTF8ToWide(chrome_frame_test::kChromeImageName),
325       UTF8ToWide(switches::kChromeFrame));
326 }
327
328 // Verifying actions
329 ACTION_P(AccExpect, matcher) {
330   scoped_refptr<AccObject> object;
331   EXPECT_TRUE(FindAccObjectInWindow(arg0, matcher, &object));
332 }
333
334 ACTION_P2(AccExpectInRenderer, mock, matcher) {
335   AccInWindow<void>(AccExpect(matcher),
336                     mock->event_sink()->GetRendererWindow());
337 }
338
339 ACTION_P(ExpectRendererHasFocus, mock) {
340   mock->event_sink()->ExpectRendererWindowHasFocus();
341 }
342
343 ACTION_P(VerifyAddressBarUrl, mock) {
344   mock->event_sink()->ExpectAddressBarUrl(std::wstring(arg1));
345 }
346
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);
350 }
351
352 ACTION_P5(ValidateWindowSize, mock, left, top, width, height) {
353   int actual_left = 0;
354   int actual_top = 0;
355   int actual_width = 0;
356   int actual_height = 0;
357
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
363
364   EXPECT_GE(actual_left, left);
365   EXPECT_GE(actual_top, top);
366
367   EXPECT_GE(actual_width, width);
368   EXPECT_GE(actual_height, height);
369 }
370
371 ACTION_P(VerifyAddressBarUrlWithGcf, mock) {
372   std::wstring expected_url = L"gcf:";
373   expected_url += arg1;
374   mock->event_sink()->ExpectAddressBarUrl(expected_url);
375 }
376
377 ACTION_P2(ExpectDocumentReadystate, mock, ready_state) {
378   mock->ExpectDocumentReadystate(ready_state);
379 }
380
381 ACTION_P(VerifySelectedText, expected_text) {
382   std::wstring actual_text;
383   bool got_selection = arg1->GetSelectedText(&actual_text);
384   EXPECT_TRUE(got_selection);
385   if (got_selection) {
386     EXPECT_EQ(expected_text, actual_text);
387   }
388 }
389
390 // Polling actions
391
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();
398       break;
399     }
400     base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(200));
401   }
402   mock->event_sink()->CloseWebBrowser();
403 }
404
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();
412       break;
413     }
414   }
415 }
416
417 // Flaky actions
418
419 ACTION_P(SetFocusToRenderer, mock) {
420   simulate_input::SetKeyboardFocusToWindow(
421       mock->event_sink()->GetRendererWindow());
422 }
423
424 ACTION_P4(DelaySendChar, loop, delay, c, mod) {
425   loop->PostDelayedTask(
426       FROM_HERE, base::Bind(simulate_input::SendCharA, c, mod), delay);
427 }
428
429 ACTION_P4(DelaySendScanCode, loop, delay, c, mod) {
430   loop->PostDelayedTask(
431       FROM_HERE, base::Bind(simulate_input::SendScanCode, c, mod), delay);
432 }
433
434 // This function selects the address bar via the Alt+d shortcut.
435 ACTION_P3(TypeUrlInAddressBar, loop, url, delay) {
436   loop->PostDelayedTask(
437       FROM_HERE,
438       base::Bind(simulate_input::SendCharA, 'd', simulate_input::ALT), delay);
439
440   const base::TimeDelta kInterval = base::TimeDelta::FromMilliseconds(500);
441   base::TimeDelta next_delay = delay + kInterval;
442
443   loop->PostDelayedTask(
444       FROM_HERE, base::Bind(simulate_input::SendStringW, url), next_delay);
445
446   next_delay = next_delay + kInterval;
447
448   loop->PostDelayedTask(
449       FROM_HERE,
450       base::Bind(simulate_input::SendCharA, VK_RETURN, simulate_input::NONE),
451       next_delay);
452 }
453
454 }  // namespace chrome_frame_test
455
456 #endif  // CHROME_FRAME_TEST_MOCK_IE_EVENT_SINK_ACTIONS_H_