• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "chrome/test/base/view_event_test_base.h"
6 
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "chrome/test/base/interactive_test_utils.h"
12 #include "chrome/test/base/testing_browser_process.h"
13 #include "chrome/test/base/ui_test_utils.h"
14 #include "content/public/browser/browser_thread.h"
15 #include "ui/base/ime/input_method_initializer.h"
16 #include "ui/base/test/ui_controls.h"
17 #include "ui/compositor/test/context_factories_for_test.h"
18 #include "ui/message_center/message_center.h"
19 #include "ui/views/view.h"
20 #include "ui/views/widget/desktop_aura/desktop_screen.h"
21 #include "ui/views/widget/widget.h"
22 
23 #if defined(USE_ASH)
24 #include "ash/shell.h"
25 #include "ash/test/test_session_state_delegate.h"
26 #include "ash/test/test_shell_delegate.h"
27 #endif
28 
29 #if defined(USE_AURA)
30 #include "ui/aura/client/event_client.h"
31 #include "ui/aura/env.h"
32 #include "ui/aura/root_window.h"
33 #include "ui/aura/test/aura_test_helper.h"
34 #endif
35 
36 #if defined(OS_CHROMEOS)
37 #include "chromeos/audio/cras_audio_handler.h"
38 #include "chromeos/network/network_handler.h"
39 #endif
40 
41 namespace {
42 
43 // View subclass that allows you to specify the preferred size.
44 class TestView : public views::View {
45  public:
TestView()46   TestView() {}
47 
SetPreferredSize(const gfx::Size & size)48   void SetPreferredSize(const gfx::Size& size) {
49     preferred_size_ = size;
50     PreferredSizeChanged();
51   }
52 
GetPreferredSize()53   virtual gfx::Size GetPreferredSize() OVERRIDE {
54     if (!preferred_size_.IsEmpty())
55       return preferred_size_;
56     return View::GetPreferredSize();
57   }
58 
Layout()59   virtual void Layout() OVERRIDE {
60     View* child_view = child_at(0);
61     child_view->SetBounds(0, 0, width(), height());
62   }
63 
64  private:
65   gfx::Size preferred_size_;
66 
67   DISALLOW_COPY_AND_ASSIGN(TestView);
68 };
69 
70 // Delay in background thread before posting mouse move.
71 const int kMouseMoveDelayMS = 200;
72 
73 }  // namespace
74 
ViewEventTestBase()75 ViewEventTestBase::ViewEventTestBase()
76   : window_(NULL),
77     content_view_(NULL) {
78   // The TestingBrowserProcess must be created in the constructor because there
79   // are tests that require it before SetUp() is called.
80   TestingBrowserProcess::CreateInstance();
81 }
82 
Done()83 void ViewEventTestBase::Done() {
84   base::MessageLoop::current()->Quit();
85 
86 #if defined(OS_WIN) && !defined(USE_AURA)
87   // We need to post a message to tickle the Dispatcher getting called and
88   // exiting out of the nested loop. Without this the quit never runs.
89   if (window_)
90     PostMessage(window_->GetNativeWindow(), WM_USER, 0, 0);
91 #endif
92 
93   // If we're in a nested message loop, as is the case with menus, we
94   // need to quit twice. The second quit does that for us. Finish all
95   // pending UI events before posting closure because events it may be
96   // executed before UI events are executed.
97   ui_controls::RunClosureAfterAllPendingUIEvents(
98       base::MessageLoop::QuitClosure());
99 }
100 
SetUp()101 void ViewEventTestBase::SetUp() {
102   views::ViewsDelegate::views_delegate = &views_delegate_;
103   ui::InitializeInputMethodForTesting();
104   gfx::NativeView context = NULL;
105 
106 #if defined(USE_ASH)
107   // The ContextFactory must exist before any Compositors are created.
108   bool allow_test_contexts = true;
109   ui::InitializeContextFactoryForTests(allow_test_contexts);
110 #if defined(OS_WIN)
111   // http://crbug.com/154081 use ash::Shell code path below on win_ash bots when
112   // interactive_ui_tests is brought up on that platform.
113   gfx::Screen::SetScreenInstance(
114       gfx::SCREEN_TYPE_NATIVE, views::CreateDesktopScreen());
115 
116 #else  // !OS_WIN
117   // Ash Shell can't just live on its own without a browser process, we need to
118   // also create the message center.
119   message_center::MessageCenter::Initialize();
120 #if defined(OS_CHROMEOS)
121   chromeos::CrasAudioHandler::InitializeForTesting();
122   chromeos::NetworkHandler::Initialize();
123 #endif  // OS_CHROMEOS
124   ash::test::TestShellDelegate* shell_delegate =
125       new ash::test::TestShellDelegate();
126   ash::Shell::CreateInstance(shell_delegate);
127   shell_delegate->test_session_state_delegate()
128       ->SetActiveUserSessionStarted(true);
129   context = ash::Shell::GetPrimaryRootWindow();
130 #endif  // !OS_WIN
131   aura::Env::CreateInstance();
132 #elif defined(USE_AURA)
133   // Instead of using the ash shell, use an AuraTestHelper to create and manage
134   // the test screen.
135   aura_test_helper_.reset(
136       new aura::test::AuraTestHelper(base::MessageLoopForUI::current()));
137   aura_test_helper_->SetUp();
138   context = aura_test_helper_->root_window();
139 #endif  // !USE_ASH && USE_AURA
140 
141   window_ = views::Widget::CreateWindowWithContext(this, context);
142 }
143 
TearDown()144 void ViewEventTestBase::TearDown() {
145   if (window_) {
146 #if defined(OS_WIN) && !defined(USE_AURA)
147     DestroyWindow(window_->GetNativeWindow());
148 #else
149     window_->Close();
150     content::RunAllPendingInMessageLoop();
151 #endif
152     window_ = NULL;
153   }
154 
155 #if defined(USE_ASH)
156 #if !defined(OS_WIN)
157   ash::Shell::DeleteInstance();
158 #if defined(OS_CHROMEOS)
159   chromeos::NetworkHandler::Shutdown();
160   chromeos::CrasAudioHandler::Shutdown();
161 #endif
162   // Ash Shell can't just live on its own without a browser process, we need to
163   // also shut down the message center.
164   message_center::MessageCenter::Shutdown();
165 #endif  // !OS_WIN
166   aura::Env::DeleteInstance();
167   ui::TerminateContextFactoryForTests();
168 #elif defined(USE_AURA)
169   aura_test_helper_->TearDown();
170 #endif  // !USE_ASH && USE_AURA
171 
172   ui::ShutdownInputMethodForTesting();
173   views::ViewsDelegate::views_delegate = NULL;
174 }
175 
CanResize() const176 bool ViewEventTestBase::CanResize() const {
177   return true;
178 }
179 
GetContentsView()180 views::View* ViewEventTestBase::GetContentsView() {
181   if (!content_view_) {
182     // Wrap the real view (as returned by CreateContentsView) in a View so
183     // that we can customize the preferred size.
184     TestView* test_view = new TestView();
185     test_view->SetPreferredSize(GetPreferredSize());
186     test_view->AddChildView(CreateContentsView());
187     content_view_ = test_view;
188   }
189   return content_view_;
190 }
191 
GetWidget() const192 const views::Widget* ViewEventTestBase::GetWidget() const {
193   return content_view_->GetWidget();
194 }
195 
GetWidget()196 views::Widget* ViewEventTestBase::GetWidget() {
197   return content_view_->GetWidget();
198 }
199 
~ViewEventTestBase()200 ViewEventTestBase::~ViewEventTestBase() {
201   TestingBrowserProcess::DeleteInstance();
202 }
203 
StartMessageLoopAndRunTest()204 void ViewEventTestBase::StartMessageLoopAndRunTest() {
205   ASSERT_TRUE(
206       ui_test_utils::ShowAndFocusNativeWindow(window_->GetNativeWindow()));
207 
208   // Flush any pending events to make sure we start with a clean slate.
209   content::RunAllPendingInMessageLoop();
210 
211   // Schedule a task that starts the test. Need to do this as we're going to
212   // run the message loop.
213   base::MessageLoop::current()->PostTask(
214       FROM_HERE, base::Bind(&ViewEventTestBase::DoTestOnMessageLoop, this));
215 
216   content::RunMessageLoop();
217 }
218 
GetPreferredSize()219 gfx::Size ViewEventTestBase::GetPreferredSize() {
220   return gfx::Size();
221 }
222 
ScheduleMouseMoveInBackground(int x,int y)223 void ViewEventTestBase::ScheduleMouseMoveInBackground(int x, int y) {
224   if (!dnd_thread_.get()) {
225     dnd_thread_.reset(new base::Thread("mouse-move-thread"));
226     dnd_thread_->Start();
227   }
228   dnd_thread_->message_loop()->PostDelayedTask(
229       FROM_HERE,
230       base::Bind(base::IgnoreResult(&ui_controls::SendMouseMove), x, y),
231       base::TimeDelta::FromMilliseconds(kMouseMoveDelayMS));
232 }
233 
StopBackgroundThread()234 void ViewEventTestBase::StopBackgroundThread() {
235   dnd_thread_.reset(NULL);
236 }
237 
RunTestMethod(const base::Closure & task)238 void ViewEventTestBase::RunTestMethod(const base::Closure& task) {
239   StopBackgroundThread();
240 
241   task.Run();
242   if (HasFatalFailure())
243     Done();
244 }
245