Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(194)

Side by Side Diff: content/browser/frame_host/interstitial_page_impl_browsertest.cc

Issue 1162373002: Make some editing/selection functions accessible to c/b/renderer_host/ (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed more review comments Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 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 #include "content/browser/frame_host/interstitial_page_impl.h"
6
7 #include "base/strings/utf_string_conversions.h"
8 #include "base/synchronization/waitable_event.h"
9 #include "content/browser/web_contents/web_contents_impl.h"
10 #include "content/common/clipboard_messages.h"
11 #include "content/common/frame_messages.h"
12 #include "content/public/browser/browser_message_filter.h"
13 #include "content/public/browser/interstitial_page_delegate.h"
14 #include "content/public/test/browser_test_utils.h"
15 #include "content/public/test/content_browser_test.h"
16 #include "content/public/test/test_utils.h"
17 #include "content/shell/browser/shell.h"
18 #include "ipc/message_filter.h"
19 #include "ui/base/clipboard/scoped_clipboard_writer.h"
20 #include "ui/base/test/test_clipboard.h"
21
22 namespace content {
23
24 namespace {
25
26 class TestInterstitialPageDelegate : public InterstitialPageDelegate {
27 private:
28 // InterstitialPageDelegate:
29 std::string GetHTMLContents() override {
30 return "<html>"
31 "<head>"
32 "<title>LOADED</title>"
33 "<script>"
34 "function focus_select_input() {"
35 " document.getElementById('input').select();"
36 "}"
37 "function set_input_text(text) {"
38 " document.getElementById('input').value = text;"
39 "}"
40 "function get_input_text() {"
41 " window.domAutomationController.send("
42 " document.getElementById('input').value);"
43 "}"
44 "</script>"
45 "</head>"
46 "<body>"
47 " <input id='input' oninput='document.title=\"TEXT_CHANGED\"'>"
48 "</body>"
49 "</html>";
50 }
51 };
52
53 // A title watcher for interstitial pages. The existing TitleWatcher does not
54 // work for interstitial pages. Note that this title watcher waits for the
55 // title update IPC message not the actual title update. So, the new title is
56 // probably not propagated completely, yet.
57 class InterstitialTitleUpdateWatcher : public BrowserMessageFilter {
58 public:
59 explicit InterstitialTitleUpdateWatcher(InterstitialPage* interstitial)
60 : BrowserMessageFilter(FrameMsgStart) {
61 interstitial->GetMainFrame()->GetProcess()->AddFilter(this);
62 }
63
64 void InitWait(const std::string& expected_title) {
65 DCHECK(!run_loop_);
66 expected_title_ = base::UTF8ToUTF16(expected_title);
67 run_loop_.reset(new base::RunLoop());
68 }
69
70 void Wait() {
71 DCHECK(run_loop_);
72 run_loop_->Run();
73 run_loop_.reset();
74 }
75
76 private:
77 ~InterstitialTitleUpdateWatcher() override {}
78
79 void OnTitleUpdateReceived(const base::string16& title) {
80 DCHECK(run_loop_);
81 if (title == expected_title_)
82 run_loop_->Quit();
83 }
84
85 // BrowserMessageFilter:
86 bool OnMessageReceived(const IPC::Message& message) override {
87 if (!run_loop_)
88 return false;
89
90 if (message.type() == FrameHostMsg_UpdateTitle::ID) {
91 FrameHostMsg_UpdateTitle::Param params;
92 if (FrameHostMsg_UpdateTitle::Read(&message, &params)) {
93 BrowserThread::PostTask(
94 BrowserThread::UI, FROM_HERE,
95 base::Bind(&InterstitialTitleUpdateWatcher::OnTitleUpdateReceived,
96 this, base::get<0>(params)));
97 }
98 }
99 return false;
100 }
101
102 base::string16 expected_title_;
103 scoped_ptr<base::RunLoop> run_loop_;
104
105 DISALLOW_COPY_AND_ASSIGN(InterstitialTitleUpdateWatcher);
106 };
107
108 // A message filter that watches for WriteText and CommitWrite clipboard IPC
109 // messages to make sure cut/copy is working properly. It will mark these events
110 // as handled to prevent modification of the actual clipboard.
111 class ClipboardMessageWatcher : public IPC::MessageFilter {
112 public:
113 explicit ClipboardMessageWatcher(InterstitialPage* interstitial) {
114 interstitial->GetMainFrame()->GetProcess()->GetChannel()->AddFilter(this);
115 }
116
117 void InitWait() {
118 DCHECK(!run_loop_);
119 run_loop_.reset(new base::RunLoop());
120 }
121
122 void WaitForWriteCommit() {
123 DCHECK(run_loop_);
124 run_loop_->Run();
125 run_loop_.reset();
126 }
127
128 const base::string16& last_text() const { return last_text_; }
129
130 private:
131 ~ClipboardMessageWatcher() override {}
132
133 void OnWriteText(const base::string16& text) { last_text_ = text; }
134
135 void OnCommitWrite() {
136 DCHECK(run_loop_);
137 run_loop_->Quit();
138 }
139
140 // IPC::MessageFilter:
141 bool OnMessageReceived(const IPC::Message& message) override {
142 if (!run_loop_)
143 return false;
144
145 if (message.type() == ClipboardHostMsg_WriteText::ID) {
146 ClipboardHostMsg_WriteText::Param params;
147 if (ClipboardHostMsg_WriteText::Read(&message, &params)) {
148 BrowserThread::PostTask(
149 BrowserThread::UI, FROM_HERE,
150 base::Bind(&ClipboardMessageWatcher::OnWriteText, this,
151 base::get<1>(params)));
152 }
153 return true;
154 }
155 if (message.type() == ClipboardHostMsg_CommitWrite::ID) {
156 BrowserThread::PostTask(
157 BrowserThread::UI, FROM_HERE,
158 base::Bind(&ClipboardMessageWatcher::OnCommitWrite, this));
159 return true;
160 }
161 return false;
162 }
163
164 scoped_ptr<base::RunLoop> run_loop_;
165 base::string16 last_text_;
166
167 DISALLOW_COPY_AND_ASSIGN(ClipboardMessageWatcher);
168 };
169
170 } // namespace
171
172 class InterstitialPageImplTest : public ContentBrowserTest {
173 public:
174 InterstitialPageImplTest()
175 : clipboard_message_watcher_(nullptr), title_update_watcher_(nullptr) {}
176
177 ~InterstitialPageImplTest() override {}
178
179 protected:
180 void SetUpTestClipboard() {
181 #if defined(OS_WIN)
182 // On Windows, clipboard reads are handled on the IO thread. So, the test
183 // clipboard should be created for the IO thread.
184 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
185 RunTaskOnIOThreadAndWait(
186 base::Bind(&InterstitialPageImplTest::SetUpTestClipboard, this));
187 return;
188 }
189 #endif
190 ui::TestClipboard::CreateForCurrentThread();
191 }
192
193 void TearDownTestClipboard() {
194 #if defined(OS_WIN)
195 // On Windows, test clipboard is created for the IO thread. So, destroy it
196 // for the IO thread, too.
197 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
198 RunTaskOnIOThreadAndWait(
199 base::Bind(&InterstitialPageImplTest::TearDownTestClipboard, this));
200 return;
201 }
202 #endif
203 ui::Clipboard::DestroyClipboardForCurrentThread();
204 }
205
206 void SetClipboardText(const std::string& text) {
207 #if defined(OS_WIN)
208 // On Windows, clipboard reads are handled on the IO thread. So, set the
209 // text for the IO thread clipboard.
210 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
211 RunTaskOnIOThreadAndWait(
212 base::Bind(&InterstitialPageImplTest::SetClipboardText, this, text));
213 return;
214 }
215 #endif
216 ui::ScopedClipboardWriter clipboard_writer(ui::CLIPBOARD_TYPE_COPY_PASTE);
217 clipboard_writer.WriteText(base::ASCIIToUTF16(text));
218 }
219
220 void SetUpInterstitialPage() {
221 WebContentsImpl* web_contents =
222 static_cast<WebContentsImpl*>(shell()->web_contents());
223
224 // Create the interstitial page.
225 TestInterstitialPageDelegate* interstitial_delegate =
226 new TestInterstitialPageDelegate;
227 GURL url("http://interstitial");
228 interstitial_.reset(new InterstitialPageImpl(
229 web_contents, static_cast<RenderWidgetHostDelegate*>(web_contents),
230 true, url, interstitial_delegate));
231 interstitial_->Show();
232 WaitForInterstitialAttach(web_contents);
233
234 // Focus the interstitial frame
235 FrameTree* frame_tree = static_cast<RenderViewHostDelegate*>(
236 interstitial_.get())->GetFrameTree();
237 frame_tree->SetFocusedFrame(frame_tree->root());
238
239 clipboard_message_watcher_ =
240 new ClipboardMessageWatcher(interstitial_.get());
241 title_update_watcher_ =
242 new InterstitialTitleUpdateWatcher(interstitial_.get());
243
244 // Wait until page loads completely.
245 if (web_contents->GetTitle() != base::ASCIIToUTF16("LOADED")) {
246 title_update_watcher_->InitWait("LOADED");
247 title_update_watcher_->Wait();
248 }
249 }
250
251 void TearDownInterstitialPage() {
252 // Close the interstitial.
253 interstitial_->DontProceed();
254 WaitForInterstitialDetach(shell()->web_contents());
255 interstitial_.reset();
256 }
257
258 bool FocusInputAndSelectText() {
259 return ExecuteScript(interstitial_->GetMainFrame(), "focus_select_input()");
260 }
261
262 bool GetInputText(std::string* input_text) {
263 return ExecuteScriptAndExtractString(interstitial_->GetMainFrame(),
264 "get_input_text()", input_text);
265 }
266
267 bool SetInputText(const std::string& text) {
268 return ExecuteScript(interstitial_->GetMainFrame(),
269 "set_input_text('" + text + "')");
270 }
271
272 std::string PerformCut() {
273 clipboard_message_watcher_->InitWait();
274 title_update_watcher_->InitWait("TEXT_CHANGED");
275 RenderFrameHostImpl* rfh =
276 static_cast<RenderFrameHostImpl*>(interstitial_->GetMainFrame());
277 rfh->GetRenderWidgetHost()->delegate()->Cut();
278 clipboard_message_watcher_->WaitForWriteCommit();
279 title_update_watcher_->Wait();
280 return base::UTF16ToUTF8(clipboard_message_watcher_->last_text());
dcheng 2015/07/02 16:53:29 Just save last_text() as a std::string and convert
mohsen 2015/07/02 17:03:45 Done.
281 }
282
283 std::string PerformCopy() {
284 clipboard_message_watcher_->InitWait();
285 RenderFrameHostImpl* rfh =
286 static_cast<RenderFrameHostImpl*>(interstitial_->GetMainFrame());
287 rfh->GetRenderWidgetHost()->delegate()->Copy();
288 clipboard_message_watcher_->WaitForWriteCommit();
289 return base::UTF16ToUTF8(clipboard_message_watcher_->last_text());
290 }
291
292 void PerformPaste() {
293 title_update_watcher_->InitWait("TEXT_CHANGED");
294 RenderFrameHostImpl* rfh =
295 static_cast<RenderFrameHostImpl*>(interstitial_->GetMainFrame());
296 rfh->GetRenderWidgetHost()->delegate()->Paste();
297 title_update_watcher_->Wait();
298 }
299
300 private:
301 void RunTaskOnIOThreadAndWait(const base::Closure& task) {
302 base::WaitableEvent completion(false, false);
303 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
304 base::Bind(&InterstitialPageImplTest::RunTask, this,
305 task, &completion));
306 completion.Wait();
307 }
308
309 void RunTask(const base::Closure& task, base::WaitableEvent* completion) {
310 task.Run();
311 completion->Signal();
312 }
313
314 scoped_ptr<InterstitialPageImpl> interstitial_;
315 ClipboardMessageWatcher* clipboard_message_watcher_;
316 InterstitialTitleUpdateWatcher* title_update_watcher_;
317
318 DISALLOW_COPY_AND_ASSIGN(InterstitialPageImplTest);
319 };
320
321 IN_PROC_BROWSER_TEST_F(InterstitialPageImplTest, Cut) {
322 SetUpInterstitialPage();
323
324 ASSERT_TRUE(SetInputText("text-to-cut"));
325 ASSERT_TRUE(FocusInputAndSelectText());
326
327 std::string clipboard_text = PerformCut();
328 EXPECT_EQ("text-to-cut", clipboard_text);
329
330 std::string input_text;
331 ASSERT_TRUE(GetInputText(&input_text));
332 EXPECT_EQ(std::string(), input_text);
333
334 TearDownInterstitialPage();
335 }
336
337 IN_PROC_BROWSER_TEST_F(InterstitialPageImplTest, Copy) {
338 SetUpInterstitialPage();
339
340 ASSERT_TRUE(SetInputText("text-to-copy"));
341 ASSERT_TRUE(FocusInputAndSelectText());
342
343 std::string clipboard_text = PerformCopy();
344 EXPECT_EQ("text-to-copy", clipboard_text);
345
346 std::string input_text;
347 ASSERT_TRUE(GetInputText(&input_text));
348 EXPECT_EQ("text-to-copy", input_text);
349
350 TearDownInterstitialPage();
351 }
352
353 IN_PROC_BROWSER_TEST_F(InterstitialPageImplTest, Paste) {
354 SetUpTestClipboard();
355 SetUpInterstitialPage();
356
357 SetClipboardText("text-to-paste");
358
359 ASSERT_TRUE(SetInputText(std::string()));
360 ASSERT_TRUE(FocusInputAndSelectText());
361
362 PerformPaste();
363
364 std::string input_text;
365 ASSERT_TRUE(GetInputText(&input_text));
366 EXPECT_EQ("text-to-paste", input_text);
367
368 TearDownInterstitialPage();
369 TearDownTestClipboard();
370 }
371
372 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698