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