Updating trunk VERSION from 804.0 to 805.0
[chromium-blink-merge.git] / chrome / test / render_view_test.cc
blob78004b94553e93961a056adb7c4288be95e84d9e
1 // Copyright (c) 2011 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 #include "chrome/test/render_view_test.h"
7 #include "chrome/browser/extensions/extension_function_dispatcher.h"
8 #include "chrome/common/extensions/extension.h"
9 #include "chrome/common/print_messages.h"
10 #include "chrome/common/render_messages.h"
11 #include "chrome/renderer/autofill/password_autofill_manager.h"
12 #include "chrome/renderer/extensions/event_bindings.h"
13 #include "chrome/renderer/extensions/extension_dispatcher.h"
14 #include "chrome/renderer/extensions/extension_process_bindings.h"
15 #include "chrome/renderer/extensions/js_only_v8_extensions.h"
16 #include "chrome/renderer/extensions/renderer_extension_bindings.h"
17 #include "chrome/renderer/mock_render_process.h"
18 #include "content/common/dom_storage_common.h"
19 #include "content/common/native_web_keyboard_event.h"
20 #include "content/common/renderer_preferences.h"
21 #include "content/common/view_messages.h"
22 #include "content/renderer/renderer_main_platform_delegate.h"
23 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
24 #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h"
25 #include "third_party/WebKit/Source/WebKit/chromium/public/WebKit.h"
26 #include "third_party/WebKit/Source/WebKit/chromium/public/WebScriptController.h"
27 #include "third_party/WebKit/Source/WebKit/chromium/public/WebScriptSource.h"
28 #include "third_party/WebKit/Source/WebKit/chromium/public/WebURLRequest.h"
29 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
30 #include "webkit/glue/webkit_glue.h"
32 #if defined(OS_LINUX)
33 #include "ui/base/gtk/event_synthesis_gtk.h"
34 #endif
36 using WebKit::WebFrame;
37 using WebKit::WebInputEvent;
38 using WebKit::WebMouseEvent;
39 using WebKit::WebScriptController;
40 using WebKit::WebScriptSource;
41 using WebKit::WebString;
42 using WebKit::WebURLRequest;
43 using autofill::AutofillAgent;
44 using autofill::PasswordAutofillManager;
46 namespace {
47 const int32 kRouteId = 5;
48 const int32 kOpenerId = 7;
49 } // namespace
51 RenderViewTest::RenderViewTest() : extension_dispatcher_(NULL) {
54 RenderViewTest::~RenderViewTest() {
57 void RenderViewTest::ProcessPendingMessages() {
58 msg_loop_.PostTask(FROM_HERE, new MessageLoop::QuitTask());
59 msg_loop_.Run();
62 WebFrame* RenderViewTest::GetMainFrame() {
63 return view_->webview()->mainFrame();
66 void RenderViewTest::ExecuteJavaScript(const char* js) {
67 GetMainFrame()->executeScript(WebScriptSource(WebString::fromUTF8(js)));
70 bool RenderViewTest::ExecuteJavaScriptAndReturnIntValue(
71 const string16& script,
72 int* int_result) {
73 v8::Handle<v8::Value> result =
74 GetMainFrame()->executeScriptAndReturnValue(WebScriptSource(script));
75 if (result.IsEmpty() || !result->IsInt32())
76 return false;
78 if (int_result)
79 *int_result = result->Int32Value();
81 return true;
84 void RenderViewTest::LoadHTML(const char* html) {
85 std::string url_str = "data:text/html;charset=utf-8,";
86 url_str.append(html);
87 GURL url(url_str);
89 GetMainFrame()->loadRequest(WebURLRequest(url));
91 // The load actually happens asynchronously, so we pump messages to process
92 // the pending continuation.
93 ProcessPendingMessages();
96 void RenderViewTest::SetUp() {
97 content::GetContentClient()->set_renderer(&chrome_content_renderer_client_);
98 extension_dispatcher_ = new ExtensionDispatcher();
99 chrome_content_renderer_client_.SetExtensionDispatcher(extension_dispatcher_);
100 sandbox_init_wrapper_.reset(new SandboxInitWrapper());
101 command_line_.reset(new CommandLine(CommandLine::NO_PROGRAM));
102 params_.reset(new MainFunctionParams(*command_line_, *sandbox_init_wrapper_,
103 NULL));
104 platform_.reset(new RendererMainPlatformDelegate(*params_));
105 platform_->PlatformInitialize();
107 // Setting flags and really doing anything with WebKit is fairly fragile and
108 // hacky, but this is the world we live in...
109 webkit_glue::SetJavaScriptFlags(" --expose-gc");
110 WebKit::initialize(&webkitclient_);
111 WebScriptController::registerExtension(JsonSchemaJsV8Extension::Get());
112 WebScriptController::registerExtension(EventBindings::Get(
113 extension_dispatcher_));
114 WebScriptController::registerExtension(ExtensionApiTestV8Extension::Get());
115 WebScriptController::registerExtension(ExtensionProcessBindings::Get(
116 extension_dispatcher_));
117 WebScriptController::registerExtension(RendererExtensionBindings::Get(
118 extension_dispatcher_));
119 EventBindings::SetRenderThread(&render_thread_);
121 mock_process_.reset(new MockRenderProcess);
123 render_thread_.set_routing_id(kRouteId);
125 // This needs to pass the mock render thread to the view.
126 view_ = RenderView::Create(&render_thread_,
128 gfx::kNullPluginWindow,
129 kOpenerId,
130 RendererPreferences(),
131 WebPreferences(),
132 new SharedRenderViewCounter(0),
133 kRouteId,
134 kInvalidSessionStorageNamespaceId,
135 string16());
137 // Attach a pseudo keyboard device to this object.
138 mock_keyboard_.reset(new MockKeyboard());
140 // RenderView doesn't expose it's PasswordAutofillManager or
141 // AutofillAgent objects, because it has no need to store them directly
142 // (they're stored as RenderViewObserver*). So just create another set.
143 password_autofill_ = new PasswordAutofillManager(view_);
144 autofill_agent_ = new AutofillAgent(view_, password_autofill_);
147 void RenderViewTest::TearDown() {
148 // Try very hard to collect garbage before shutting down.
149 GetMainFrame()->collectGarbage();
150 GetMainFrame()->collectGarbage();
152 render_thread_.SendCloseMessage();
154 // Run the loop so the release task from the renderwidget executes.
155 ProcessPendingMessages();
157 EventBindings::SetRenderThread(NULL);
159 view_ = NULL;
161 mock_process_.reset();
163 // After resetting the view_ and mock_process_ we may get some new tasks
164 // which need to be processed before shutting down WebKit
165 // (http://crbug.com/21508).
166 msg_loop_.RunAllPending();
168 WebKit::shutdown();
170 mock_keyboard_.reset();
172 platform_->PlatformUninitialize();
173 platform_.reset();
174 params_.reset();
175 command_line_.reset();
176 sandbox_init_wrapper_.reset();
178 extension_dispatcher_->OnRenderProcessShutdown();
179 extension_dispatcher_ = NULL;
182 int RenderViewTest::SendKeyEvent(MockKeyboard::Layout layout,
183 int key_code,
184 MockKeyboard::Modifiers modifiers,
185 std::wstring* output) {
186 #if defined(OS_WIN)
187 // Retrieve the Unicode character for the given tuple (keyboard-layout,
188 // key-code, and modifiers).
189 // Exit when a keyboard-layout driver cannot assign a Unicode character to
190 // the tuple to prevent sending an invalid key code to the RenderView object.
191 CHECK(mock_keyboard_.get());
192 CHECK(output);
193 int length = mock_keyboard_->GetCharacters(layout, key_code, modifiers,
194 output);
195 if (length != 1)
196 return -1;
198 // Create IPC messages from Windows messages and send them to our
199 // back-end.
200 // A keyboard event of Windows consists of three Windows messages:
201 // WM_KEYDOWN, WM_CHAR, and WM_KEYUP.
202 // WM_KEYDOWN and WM_KEYUP sends virtual-key codes. On the other hand,
203 // WM_CHAR sends a composed Unicode character.
204 NativeWebKeyboardEvent keydown_event(NULL, WM_KEYDOWN, key_code, 0);
205 SendNativeKeyEvent(keydown_event);
207 NativeWebKeyboardEvent char_event(NULL, WM_CHAR, (*output)[0], 0);
208 SendNativeKeyEvent(char_event);
210 NativeWebKeyboardEvent keyup_event(NULL, WM_KEYUP, key_code, 0);
211 SendNativeKeyEvent(keyup_event);
213 return length;
214 #elif defined(OS_LINUX)
215 // We ignore |layout|, which means we are only testing the layout of the
216 // current locale. TODO(estade): fix this to respect |layout|.
217 std::vector<GdkEvent*> events;
218 ui::SynthesizeKeyPressEvents(
219 NULL, static_cast<ui::KeyboardCode>(key_code),
220 modifiers & (MockKeyboard::LEFT_CONTROL | MockKeyboard::RIGHT_CONTROL),
221 modifiers & (MockKeyboard::LEFT_SHIFT | MockKeyboard::RIGHT_SHIFT),
222 modifiers & (MockKeyboard::LEFT_ALT | MockKeyboard::RIGHT_ALT),
223 &events);
225 guint32 unicode_key = 0;
226 for (size_t i = 0; i < events.size(); ++i) {
227 // Only send the up/down events for key press itself (skip the up/down
228 // events for the modifier keys).
229 if ((i + 1) == (events.size() / 2) || i == (events.size() / 2)) {
230 unicode_key = gdk_keyval_to_unicode(events[i]->key.keyval);
231 NativeWebKeyboardEvent webkit_event(&events[i]->key);
232 SendNativeKeyEvent(webkit_event);
234 // Need to add a char event after the key down.
235 if (webkit_event.type == WebKit::WebInputEvent::RawKeyDown) {
236 NativeWebKeyboardEvent char_event = webkit_event;
237 char_event.type = WebKit::WebInputEvent::Char;
238 char_event.skip_in_browser = true;
239 SendNativeKeyEvent(char_event);
242 gdk_event_free(events[i]);
245 *output = std::wstring(1, unicode_key);
246 return 1;
247 #else
248 NOTIMPLEMENTED();
249 return L'\0';
250 #endif
253 void RenderViewTest::SendNativeKeyEvent(
254 const NativeWebKeyboardEvent& key_event) {
255 scoped_ptr<IPC::Message> input_message(new ViewMsg_HandleInputEvent(0));
256 input_message->WriteData(reinterpret_cast<const char*>(&key_event),
257 sizeof(WebKit::WebKeyboardEvent));
258 view_->OnMessageReceived(*input_message);
261 const char* const kGetCoordinatesScript =
262 "(function() {"
263 " function GetCoordinates(elem) {"
264 " if (!elem)"
265 " return [ 0, 0];"
266 " var coordinates = [ elem.offsetLeft, elem.offsetTop];"
267 " var parent_coordinates = GetCoordinates(elem.offsetParent);"
268 " coordinates[0] += parent_coordinates[0];"
269 " coordinates[1] += parent_coordinates[1];"
270 " return coordinates;"
271 " };"
272 " var elem = document.getElementById('$1');"
273 " if (!elem)"
274 " return null;"
275 " var bounds = GetCoordinates(elem);"
276 " bounds[2] = elem.offsetWidth;"
277 " bounds[3] = elem.offsetHeight;"
278 " return bounds;"
279 "})();";
280 gfx::Rect RenderViewTest::GetElementBounds(const std::string& element_id) {
281 std::vector<std::string> params;
282 params.push_back(element_id);
283 std::string script =
284 ReplaceStringPlaceholders(kGetCoordinatesScript, params, NULL);
286 v8::HandleScope handle_scope;
287 v8::Handle<v8::Value> value = GetMainFrame()->executeScriptAndReturnValue(
288 WebScriptSource(WebString::fromUTF8(script)));
289 if (value.IsEmpty() || !value->IsArray())
290 return gfx::Rect();
292 v8::Handle<v8::Array> array = value.As<v8::Array>();
293 if (array->Length() != 4)
294 return gfx::Rect();
295 std::vector<int> coords;
296 for (int i = 0; i < 4; ++i) {
297 v8::Handle<v8::Number> index = v8::Number::New(i);
298 v8::Local<v8::Value> value = array->Get(index);
299 if (value.IsEmpty() || !value->IsInt32())
300 return gfx::Rect();
301 coords.push_back(value->Int32Value());
303 return gfx::Rect(coords[0], coords[1], coords[2], coords[3]);
306 bool RenderViewTest::SimulateElementClick(const std::string& element_id) {
307 gfx::Rect bounds = GetElementBounds(element_id);
308 if (bounds.IsEmpty())
309 return false;
310 WebMouseEvent mouse_event;
311 mouse_event.type = WebInputEvent::MouseDown;
312 mouse_event.button = WebMouseEvent::ButtonLeft;
313 mouse_event.x = bounds.CenterPoint().x();
314 mouse_event.y = bounds.CenterPoint().y();
315 mouse_event.clickCount = 1;
316 ViewMsg_HandleInputEvent input_event(0);
317 scoped_ptr<IPC::Message> input_message(new ViewMsg_HandleInputEvent(0));
318 input_message->WriteData(reinterpret_cast<const char*>(&mouse_event),
319 sizeof(WebMouseEvent));
320 view_->OnMessageReceived(*input_message);
321 return true;