- add sources.
[platform/framework/web/crosswalk.git] / src / content / public / test / test_utils.cc
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 #include "content/public/test/test_utils.h"
6
7 #include "base/bind.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/run_loop.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "base/values.h"
12 #include "content/public/browser/notification_service.h"
13 #include "content/public/browser/render_view_host.h"
14 #include "content/public/test/test_launcher.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16
17 namespace content {
18
19 namespace {
20
21 // Number of times to repost a Quit task so that the MessageLoop finishes up
22 // pending tasks and tasks posted by those pending tasks without risking the
23 // potential hang behavior of MessageLoop::QuitWhenIdle.
24 // The criteria for choosing this number: it should be high enough to make the
25 // quit act like QuitWhenIdle, while taking into account that any page which is
26 // animating may be rendering another frame for each quit deferral. For an
27 // animating page, the potential delay to quitting the RunLoop would be
28 // kNumQuitDeferrals * frame_render_time. Some perf tests run slow, such as
29 // 200ms/frame.
30 static const int kNumQuitDeferrals = 10;
31
32 static void DeferredQuitRunLoop(const base::Closure& quit_task,
33                                 int num_quit_deferrals) {
34   if (num_quit_deferrals <= 0) {
35     quit_task.Run();
36   } else {
37     base::MessageLoop::current()->PostTask(
38         FROM_HERE,
39         base::Bind(&DeferredQuitRunLoop, quit_task, num_quit_deferrals - 1));
40   }
41 }
42
43 void RunAllPendingMessageAndSendQuit(BrowserThread::ID thread_id,
44                                      const base::Closure& quit_task) {
45   RunAllPendingInMessageLoop();
46   BrowserThread::PostTask(thread_id, FROM_HERE, quit_task);
47 }
48
49 // Class used handle result callbacks for ExecuteScriptAndGetValue.
50 class ScriptCallback {
51  public:
52   ScriptCallback() { }
53   virtual ~ScriptCallback() { }
54   void ResultCallback(const base::Value* result);
55
56   scoped_ptr<base::Value> result() { return result_.Pass(); }
57
58  private:
59   scoped_ptr<base::Value> result_;
60
61   DISALLOW_COPY_AND_ASSIGN(ScriptCallback);
62 };
63
64 void ScriptCallback::ResultCallback(const base::Value* result) {
65   if (result)
66     result_.reset(result->DeepCopy());
67   base::MessageLoop::current()->Quit();
68 }
69
70 // Adapter that makes a WindowedNotificationObserver::ConditionTestCallback from
71 // a WindowedNotificationObserver::ConditionTestCallbackWithoutSourceAndDetails
72 // by ignoring the notification source and details.
73 bool IgnoreSourceAndDetails(
74     const WindowedNotificationObserver::
75         ConditionTestCallbackWithoutSourceAndDetails& callback,
76     const NotificationSource& source,
77     const NotificationDetails& details) {
78   return callback.Run();
79 }
80
81 }  // namespace
82
83 void RunMessageLoop() {
84   base::RunLoop run_loop;
85   RunThisRunLoop(&run_loop);
86 }
87
88 void RunThisRunLoop(base::RunLoop* run_loop) {
89   base::MessageLoop::ScopedNestableTaskAllower allow(
90       base::MessageLoop::current());
91
92   // If we're running inside a browser test, we might need to allow the test
93   // launcher to do extra work before/after running a nested message loop.
94   TestLauncherDelegate* delegate = NULL;
95 #if !defined(OS_IOS)
96   delegate = GetCurrentTestLauncherDelegate();
97 #endif
98   if (delegate)
99     delegate->PreRunMessageLoop(run_loop);
100   run_loop->Run();
101   if (delegate)
102     delegate->PostRunMessageLoop();
103 }
104
105 void RunAllPendingInMessageLoop() {
106   base::MessageLoop::current()->PostTask(
107       FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
108   RunMessageLoop();
109 }
110
111 void RunAllPendingInMessageLoop(BrowserThread::ID thread_id) {
112   if (BrowserThread::CurrentlyOn(thread_id)) {
113     RunAllPendingInMessageLoop();
114     return;
115   }
116   BrowserThread::ID current_thread_id;
117   if (!BrowserThread::GetCurrentThreadIdentifier(&current_thread_id)) {
118     NOTREACHED();
119     return;
120   }
121
122   base::RunLoop run_loop;
123   BrowserThread::PostTask(thread_id, FROM_HERE,
124       base::Bind(&RunAllPendingMessageAndSendQuit, current_thread_id,
125                  run_loop.QuitClosure()));
126   RunThisRunLoop(&run_loop);
127 }
128
129 base::Closure GetQuitTaskForRunLoop(base::RunLoop* run_loop) {
130   return base::Bind(&DeferredQuitRunLoop, run_loop->QuitClosure(),
131                     kNumQuitDeferrals);
132 }
133
134 scoped_ptr<base::Value> ExecuteScriptAndGetValue(
135     RenderViewHost* render_view_host,
136     const std::string& script) {
137   ScriptCallback observer;
138
139   render_view_host->ExecuteJavascriptInWebFrameCallbackResult(
140       string16(),  // frame_xpath,
141       UTF8ToUTF16(script),
142       base::Bind(&ScriptCallback::ResultCallback, base::Unretained(&observer)));
143   base::MessageLoop* loop = base::MessageLoop::current();
144   loop->Run();
145   return observer.result().Pass();
146 }
147
148 MessageLoopRunner::MessageLoopRunner()
149     : loop_running_(false),
150       quit_closure_called_(false) {
151 }
152
153 MessageLoopRunner::~MessageLoopRunner() {
154 }
155
156 void MessageLoopRunner::Run() {
157   // Do not run the message loop if our quit closure has already been called.
158   // This helps in scenarios where the closure has a chance to run before
159   // we Run explicitly.
160   if (quit_closure_called_)
161     return;
162
163   loop_running_ = true;
164   RunThisRunLoop(&run_loop_);
165 }
166
167 base::Closure MessageLoopRunner::QuitClosure() {
168   return base::Bind(&MessageLoopRunner::Quit, this);
169 }
170
171 void MessageLoopRunner::Quit() {
172   quit_closure_called_ = true;
173
174   // Only run the quit task if we are running the message loop.
175   if (loop_running_) {
176     GetQuitTaskForRunLoop(&run_loop_).Run();
177     loop_running_ = false;
178   }
179 }
180
181 WindowedNotificationObserver::WindowedNotificationObserver(
182     int notification_type,
183     const NotificationSource& source)
184     : seen_(false),
185       running_(false),
186       source_(NotificationService::AllSources()) {
187   AddNotificationType(notification_type, source);
188 }
189
190 WindowedNotificationObserver::WindowedNotificationObserver(
191     int notification_type,
192     const ConditionTestCallback& callback)
193     : seen_(false),
194       running_(false),
195       callback_(callback),
196       source_(NotificationService::AllSources()) {
197   AddNotificationType(notification_type, source_);
198 }
199
200 WindowedNotificationObserver::WindowedNotificationObserver(
201     int notification_type,
202     const ConditionTestCallbackWithoutSourceAndDetails& callback)
203     : seen_(false),
204       running_(false),
205       callback_(base::Bind(&IgnoreSourceAndDetails, callback)),
206       source_(NotificationService::AllSources()) {
207   registrar_.Add(this, notification_type, source_);
208 }
209
210 WindowedNotificationObserver::~WindowedNotificationObserver() {}
211
212 void WindowedNotificationObserver::AddNotificationType(
213     int notification_type,
214     const NotificationSource& source) {
215   registrar_.Add(this, notification_type, source);
216 }
217
218 void WindowedNotificationObserver::Wait() {
219   if (seen_)
220     return;
221
222   running_ = true;
223   message_loop_runner_ = new MessageLoopRunner;
224   message_loop_runner_->Run();
225   EXPECT_TRUE(seen_);
226 }
227
228 void WindowedNotificationObserver::Observe(
229     int type,
230     const NotificationSource& source,
231     const NotificationDetails& details) {
232   source_ = source;
233   details_ = details;
234   if (!callback_.is_null() && !callback_.Run(source, details))
235     return;
236
237   seen_ = true;
238   if (!running_)
239     return;
240
241   message_loop_runner_->Quit();
242   running_ = false;
243 }
244
245 }  // namespace content