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/message_loop/message_loop.h" 9#include "chrome/test/base/chrome_unit_test_suite.h" 10#include "chrome/test/base/interactive_test_utils.h" 11#include "chrome/test/base/testing_browser_process.h" 12#include "chrome/test/base/view_event_test_platform_part.h" 13#include "ui/base/ime/input_method_initializer.h" 14#include "ui/base/test/ui_controls.h" 15#include "ui/compositor/test/context_factories_for_test.h" 16#include "ui/views/view.h" 17#include "ui/views/widget/widget.h" 18 19namespace { 20 21// View subclass that allows you to specify the preferred size. 22class TestView : public views::View { 23 public: 24 TestView() {} 25 26 void SetPreferredSize(const gfx::Size& size) { 27 preferred_size_ = size; 28 PreferredSizeChanged(); 29 } 30 31 virtual gfx::Size GetPreferredSize() const OVERRIDE { 32 if (!preferred_size_.IsEmpty()) 33 return preferred_size_; 34 return View::GetPreferredSize(); 35 } 36 37 virtual void Layout() OVERRIDE { 38 View* child_view = child_at(0); 39 child_view->SetBounds(0, 0, width(), height()); 40 } 41 42 private: 43 gfx::Size preferred_size_; 44 45 DISALLOW_COPY_AND_ASSIGN(TestView); 46}; 47 48// Delay in background thread before posting mouse move. 49const int kMouseMoveDelayMS = 200; 50 51} // namespace 52 53ViewEventTestBase::ViewEventTestBase() 54 : window_(NULL), 55 content_view_(NULL) { 56 // The TestingBrowserProcess must be created in the constructor because there 57 // are tests that require it before SetUp() is called. 58 TestingBrowserProcess::CreateInstance(); 59} 60 61void ViewEventTestBase::Done() { 62 base::MessageLoop::current()->Quit(); 63 64 // If we're in a nested message loop, as is the case with menus, we 65 // need to quit twice. The second quit does that for us. Finish all 66 // pending UI events before posting closure because events it may be 67 // executed before UI events are executed. 68 ui_controls::RunClosureAfterAllPendingUIEvents( 69 base::MessageLoop::QuitClosure()); 70} 71 72void ViewEventTestBase::SetUpTestCase() { 73 ChromeUnitTestSuite::InitializeProviders(); 74 ChromeUnitTestSuite::InitializeResourceBundle(); 75} 76 77void ViewEventTestBase::SetUp() { 78 views::ViewsDelegate::views_delegate = &views_delegate_; 79 ui::InitializeInputMethodForTesting(); 80 81 // The ContextFactory must exist before any Compositors are created. 82 bool enable_pixel_output = false; 83 ui::ContextFactory* context_factory = 84 ui::InitializeContextFactoryForTests(enable_pixel_output); 85 86 platform_part_.reset(ViewEventTestPlatformPart::Create(context_factory)); 87 gfx::NativeWindow context = platform_part_->GetContext(); 88 window_ = views::Widget::CreateWindowWithContext(this, context); 89} 90 91void ViewEventTestBase::TearDown() { 92 if (window_) { 93 window_->Close(); 94 content::RunAllPendingInMessageLoop(); 95 window_ = NULL; 96 } 97 98 ui::Clipboard::DestroyClipboardForCurrentThread(); 99 platform_part_.reset(); 100 101 ui::TerminateContextFactoryForTests(); 102 103 ui::ShutdownInputMethodForTesting(); 104 views::ViewsDelegate::views_delegate = NULL; 105} 106 107bool ViewEventTestBase::CanResize() const { 108 return true; 109} 110 111views::View* ViewEventTestBase::GetContentsView() { 112 if (!content_view_) { 113 // Wrap the real view (as returned by CreateContentsView) in a View so 114 // that we can customize the preferred size. 115 TestView* test_view = new TestView(); 116 test_view->SetPreferredSize(GetPreferredSize()); 117 test_view->AddChildView(CreateContentsView()); 118 content_view_ = test_view; 119 } 120 return content_view_; 121} 122 123const views::Widget* ViewEventTestBase::GetWidget() const { 124 return content_view_->GetWidget(); 125} 126 127views::Widget* ViewEventTestBase::GetWidget() { 128 return content_view_->GetWidget(); 129} 130 131ViewEventTestBase::~ViewEventTestBase() { 132 TestingBrowserProcess::DeleteInstance(); 133} 134 135void ViewEventTestBase::StartMessageLoopAndRunTest() { 136 ASSERT_TRUE( 137 ui_test_utils::ShowAndFocusNativeWindow(window_->GetNativeWindow())); 138 139 // Flush any pending events to make sure we start with a clean slate. 140 content::RunAllPendingInMessageLoop(); 141 142 // Schedule a task that starts the test. Need to do this as we're going to 143 // run the message loop. 144 base::MessageLoop::current()->PostTask( 145 FROM_HERE, base::Bind(&ViewEventTestBase::DoTestOnMessageLoop, this)); 146 147 content::RunMessageLoop(); 148} 149 150gfx::Size ViewEventTestBase::GetPreferredSize() const { 151 return gfx::Size(); 152} 153 154void ViewEventTestBase::ScheduleMouseMoveInBackground(int x, int y) { 155 if (!dnd_thread_.get()) { 156 dnd_thread_.reset(new base::Thread("mouse-move-thread")); 157 dnd_thread_->Start(); 158 } 159 dnd_thread_->message_loop()->PostDelayedTask( 160 FROM_HERE, 161 base::Bind(base::IgnoreResult(&ui_controls::SendMouseMove), x, y), 162 base::TimeDelta::FromMilliseconds(kMouseMoveDelayMS)); 163} 164 165void ViewEventTestBase::StopBackgroundThread() { 166 dnd_thread_.reset(NULL); 167} 168 169void ViewEventTestBase::RunTestMethod(const base::Closure& task) { 170 StopBackgroundThread(); 171 172 task.Run(); 173 if (HasFatalFailure()) 174 Done(); 175} 176