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

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: Used scoped_refptr 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 std::string& last_text() const { return last_text_; }
129
130 private:
131 ~ClipboardMessageWatcher() override {}
132
133 void OnWriteText(const std::string& 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::UTF16ToUTF8(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 std::string last_text_;
166
167 DISALLOW_COPY_AND_ASSIGN(ClipboardMessageWatcher);
168 };
169
170 } // namespace
171
172 class InterstitialPageImplTest : public ContentBrowserTest {
173 public:
174 InterstitialPageImplTest() {}
175
176 ~InterstitialPageImplTest() override {}
177
178 protected:
179 void SetUpTestClipboard() {
180 #if defined(OS_WIN)
181 // On Windows, clipboard reads are handled on the IO thread. So, the test
182 // clipboard should be created for the IO thread.
183 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
184 RunTaskOnIOThreadAndWait(
185 base::Bind(&InterstitialPageImplTest::SetUpTestClipboard, this));
186 return;
187 }
188 #endif
189 ui::TestClipboard::CreateForCurrentThread();
190 }
191
192 void TearDownTestClipboard() {
193 #if defined(OS_WIN)
194 // On Windows, test clipboard is created for the IO thread. So, destroy it
195 // for the IO thread, too.
196 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
197 RunTaskOnIOThreadAndWait(
198 base::Bind(&InterstitialPageImplTest::TearDownTestClipboard, this));
199 return;
200 }
201 #endif
202 ui::Clipboard::DestroyClipboardForCurrentThread();
203 }
204
205 void SetClipboardText(const std::string& text) {
206 #if defined(OS_WIN)
207 // On Windows, clipboard reads are handled on the IO thread. So, set the
208 // text for the IO thread clipboard.
209 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
210 RunTaskOnIOThreadAndWait(
211 base::Bind(&InterstitialPageImplTest::SetClipboardText, this, text));
212 return;
213 }
214 #endif
215 ui::ScopedClipboardWriter clipboard_writer(ui::CLIPBOARD_TYPE_COPY_PASTE);
216 clipboard_writer.WriteText(base::ASCIIToUTF16(text));
217 }
218
219 void SetUpInterstitialPage() {
220 WebContentsImpl* web_contents =
221 static_cast<WebContentsImpl*>(shell()->web_contents());
222
223 // Create the interstitial page.
224 TestInterstitialPageDelegate* interstitial_delegate =
225 new TestInterstitialPageDelegate;
226 GURL url("http://interstitial");
227 interstitial_.reset(new InterstitialPageImpl(
228 web_contents, static_cast<RenderWidgetHostDelegate*>(web_contents),
229 true, url, interstitial_delegate));
230 interstitial_->Show();
231 WaitForInterstitialAttach(web_contents);
232
233 // Focus the interstitial frame
234 FrameTree* frame_tree = static_cast<RenderViewHostDelegate*>(
235 interstitial_.get())->GetFrameTree();
236 frame_tree->SetFocusedFrame(frame_tree->root());
237
238 clipboard_message_watcher_ =
239 new ClipboardMessageWatcher(interstitial_.get());
240 title_update_watcher_ =
241 new InterstitialTitleUpdateWatcher(interstitial_.get());
242
243 // Wait until page loads completely.
244 if (web_contents->GetTitle() != base::ASCIIToUTF16("LOADED")) {
245 title_update_watcher_->InitWait("LOADED");
246 title_update_watcher_->Wait();
247 }
248 }
249
250 void TearDownInterstitialPage() {
251 // Close the interstitial.
252 interstitial_->DontProceed();
253 WaitForInterstitialDetach(shell()->web_contents());
254 interstitial_.reset();
255 }
256
257 bool FocusInputAndSelectText() {
258 return ExecuteScript(interstitial_->GetMainFrame(), "focus_select_input()");
259 }
260
261 bool GetInputText(std::string* input_text) {
262 return ExecuteScriptAndExtractString(interstitial_->GetMainFrame(),
263 "get_input_text()", input_text);
264 }
265
266 bool SetInputText(const std::string& text) {
267 return ExecuteScript(interstitial_->GetMainFrame(),
268 "set_input_text('" + text + "')");
269 }
270
271 std::string PerformCut() {
272 clipboard_message_watcher_->InitWait();
273 title_update_watcher_->InitWait("TEXT_CHANGED");
274 RenderFrameHostImpl* rfh =
275 static_cast<RenderFrameHostImpl*>(interstitial_->GetMainFrame());
276 rfh->GetRenderWidgetHost()->delegate()->Cut();
277 clipboard_message_watcher_->WaitForWriteCommit();
278 title_update_watcher_->Wait();
279 return clipboard_message_watcher_->last_text();
280 }
281
282 std::string PerformCopy() {
283 clipboard_message_watcher_->InitWait();
284 RenderFrameHostImpl* rfh =
285 static_cast<RenderFrameHostImpl*>(interstitial_->GetMainFrame());
286 rfh->GetRenderWidgetHost()->delegate()->Copy();
287 clipboard_message_watcher_->WaitForWriteCommit();
288 return clipboard_message_watcher_->last_text();
289 }
290
291 void PerformPaste() {
292 title_update_watcher_->InitWait("TEXT_CHANGED");
293 RenderFrameHostImpl* rfh =
294 static_cast<RenderFrameHostImpl*>(interstitial_->GetMainFrame());
295 rfh->GetRenderWidgetHost()->delegate()->Paste();
296 title_update_watcher_->Wait();
297 }
298
299 private:
300 void RunTaskOnIOThreadAndWait(const base::Closure& task) {
301 base::WaitableEvent completion(false, false);
302 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
303 base::Bind(&InterstitialPageImplTest::RunTask, this,
304 task, &completion));
305 completion.Wait();
306 }
307
308 void RunTask(const base::Closure& task, base::WaitableEvent* completion) {
309 task.Run();
310 completion->Signal();
311 }
312
313 scoped_ptr<InterstitialPageImpl> interstitial_;
314 scoped_refptr<ClipboardMessageWatcher> clipboard_message_watcher_;
315 scoped_refptr<InterstitialTitleUpdateWatcher> title_update_watcher_;
316
317 DISALLOW_COPY_AND_ASSIGN(InterstitialPageImplTest);
318 };
319
320 IN_PROC_BROWSER_TEST_F(InterstitialPageImplTest, Cut) {
321 SetUpInterstitialPage();
322
323 ASSERT_TRUE(SetInputText("text-to-cut"));
324 ASSERT_TRUE(FocusInputAndSelectText());
325
326 std::string clipboard_text = PerformCut();
327 EXPECT_EQ("text-to-cut", clipboard_text);
328
329 std::string input_text;
330 ASSERT_TRUE(GetInputText(&input_text));
331 EXPECT_EQ(std::string(), input_text);
332
333 TearDownInterstitialPage();
334 }
335
336 IN_PROC_BROWSER_TEST_F(InterstitialPageImplTest, Copy) {
337 SetUpInterstitialPage();
338
339 ASSERT_TRUE(SetInputText("text-to-copy"));
340 ASSERT_TRUE(FocusInputAndSelectText());
341
342 std::string clipboard_text = PerformCopy();
343 EXPECT_EQ("text-to-copy", clipboard_text);
344
345 std::string input_text;
346 ASSERT_TRUE(GetInputText(&input_text));
347 EXPECT_EQ("text-to-copy", input_text);
348
349 TearDownInterstitialPage();
350 }
351
352 IN_PROC_BROWSER_TEST_F(InterstitialPageImplTest, Paste) {
353 SetUpTestClipboard();
354 SetUpInterstitialPage();
355
356 SetClipboardText("text-to-paste");
357
358 ASSERT_TRUE(SetInputText(std::string()));
359 ASSERT_TRUE(FocusInputAndSelectText());
360
361 PerformPaste();
362
363 std::string input_text;
364 ASSERT_TRUE(GetInputText(&input_text));
365 EXPECT_EQ("text-to-paste", input_text);
366
367 TearDownInterstitialPage();
368 TearDownTestClipboard();
369 }
370
371 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698