Home | History | Annotate | Download | only in base
      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/ui_test_utils.h"
     13 #include "content/public/browser/browser_thread.h"
     14 #include "ui/base/ime/input_method_initializer.h"
     15 #include "ui/base/test/ui_controls.h"
     16 #include "ui/message_center/message_center.h"
     17 #include "ui/views/view.h"
     18 #include "ui/views/widget/desktop_aura/desktop_screen.h"
     19 #include "ui/views/widget/widget.h"
     20 
     21 #if defined(USE_ASH)
     22 #include "ash/shell.h"
     23 #include "ash/test/test_session_state_delegate.h"
     24 #include "ash/test/test_shell_delegate.h"
     25 #if defined(OS_WIN)
     26 #include "ui/compositor/compositor.h"
     27 #endif
     28 #endif
     29 
     30 #if defined(USE_AURA)
     31 #include "ui/aura/client/event_client.h"
     32 #include "ui/aura/env.h"
     33 #include "ui/aura/root_window.h"
     34 #include "ui/aura/test/aura_test_helper.h"
     35 #endif
     36 
     37 #if defined(OS_CHROMEOS)
     38 #include "chromeos/audio/cras_audio_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:
     46   TestView() {}
     47 
     48   void SetPreferredSize(const gfx::Size& size) {
     49     preferred_size_ = size;
     50     PreferredSizeChanged();
     51   }
     52 
     53   virtual gfx::Size GetPreferredSize() OVERRIDE {
     54     if (!preferred_size_.IsEmpty())
     55       return preferred_size_;
     56     return View::GetPreferredSize();
     57   }
     58 
     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 
     75 ViewEventTestBase::ViewEventTestBase()
     76   : window_(NULL),
     77     content_view_(NULL) {
     78 }
     79 
     80 void ViewEventTestBase::Done() {
     81   base::MessageLoop::current()->Quit();
     82 
     83 #if defined(OS_WIN) && !defined(USE_AURA)
     84   // We need to post a message to tickle the Dispatcher getting called and
     85   // exiting out of the nested loop. Without this the quit never runs.
     86   if (window_)
     87     PostMessage(window_->GetNativeWindow(), WM_USER, 0, 0);
     88 #endif
     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::SetUp() {
     99   ui::InitializeInputMethodForTesting();
    100   gfx::NativeView context = NULL;
    101 #if defined(USE_ASH)
    102 #if defined(OS_WIN)
    103   // http://crbug.com/154081 use ash::Shell code path below on win_ash bots when
    104   // interactive_ui_tests is brought up on that platform.
    105   gfx::Screen::SetScreenInstance(
    106       gfx::SCREEN_TYPE_NATIVE, views::CreateDesktopScreen());
    107 
    108   // The ContextFactory must exist before any Compositors are created. The
    109   // ash::Shell code path below handles this, but since we skip it we must
    110   // do this here.
    111   bool allow_test_contexts = true;
    112   ui::Compositor::InitializeContextFactoryForTests(allow_test_contexts);
    113 #else  // !OS_WIN
    114   // Ash Shell can't just live on its own without a browser process, we need to
    115   // also create the message center.
    116   message_center::MessageCenter::Initialize();
    117 #if defined(OS_CHROMEOS)
    118   chromeos::CrasAudioHandler::InitializeForTesting();
    119 #endif  // OS_CHROMEOS
    120   ash::test::TestShellDelegate* shell_delegate =
    121       new ash::test::TestShellDelegate();
    122   ash::Shell::CreateInstance(shell_delegate);
    123   shell_delegate->test_session_state_delegate()
    124       ->SetActiveUserSessionStarted(true);
    125   context = ash::Shell::GetPrimaryRootWindow();
    126 #endif  // !OS_WIN
    127 #elif defined(USE_AURA)
    128   // Instead of using the ash shell, use an AuraTestHelper to create and manage
    129   // the test screen.
    130   aura_test_helper_.reset(
    131       new aura::test::AuraTestHelper(base::MessageLoopForUI::current()));
    132   aura_test_helper_->SetUp();
    133   context = aura_test_helper_->root_window();
    134 #endif  // USE_AURA
    135   window_ = views::Widget::CreateWindowWithContext(this, context);
    136 }
    137 
    138 void ViewEventTestBase::TearDown() {
    139   if (window_) {
    140 #if defined(OS_WIN) && !defined(USE_AURA)
    141     DestroyWindow(window_->GetNativeWindow());
    142 #else
    143     window_->Close();
    144     content::RunAllPendingInMessageLoop();
    145 #endif
    146     window_ = NULL;
    147   }
    148 #if defined(USE_ASH)
    149 #if defined(OS_WIN)
    150 #else
    151   ash::Shell::DeleteInstance();
    152 #if defined(OS_CHROMEOS)
    153   chromeos::CrasAudioHandler::Shutdown();
    154 #endif
    155   // Ash Shell can't just live on its own without a browser process, we need to
    156   // also shut down the message center.
    157   message_center::MessageCenter::Shutdown();
    158   aura::Env::DeleteInstance();
    159 #endif
    160 #elif defined(USE_AURA)
    161   aura_test_helper_->TearDown();
    162 #endif
    163   ui::ShutdownInputMethodForTesting();
    164 }
    165 
    166 bool ViewEventTestBase::CanResize() const {
    167   return true;
    168 }
    169 
    170 views::View* ViewEventTestBase::GetContentsView() {
    171   if (!content_view_) {
    172     // Wrap the real view (as returned by CreateContentsView) in a View so
    173     // that we can customize the preferred size.
    174     TestView* test_view = new TestView();
    175     test_view->SetPreferredSize(GetPreferredSize());
    176     test_view->AddChildView(CreateContentsView());
    177     content_view_ = test_view;
    178   }
    179   return content_view_;
    180 }
    181 
    182 const views::Widget* ViewEventTestBase::GetWidget() const {
    183   return content_view_->GetWidget();
    184 }
    185 
    186 views::Widget* ViewEventTestBase::GetWidget() {
    187   return content_view_->GetWidget();
    188 }
    189 
    190 ViewEventTestBase::~ViewEventTestBase() {
    191 }
    192 
    193 void ViewEventTestBase::StartMessageLoopAndRunTest() {
    194   ASSERT_TRUE(
    195       ui_test_utils::ShowAndFocusNativeWindow(window_->GetNativeWindow()));
    196 
    197   // Flush any pending events to make sure we start with a clean slate.
    198   content::RunAllPendingInMessageLoop();
    199 
    200   // Schedule a task that starts the test. Need to do this as we're going to
    201   // run the message loop.
    202   base::MessageLoop::current()->PostTask(
    203       FROM_HERE, base::Bind(&ViewEventTestBase::DoTestOnMessageLoop, this));
    204 
    205   content::RunMessageLoop();
    206 }
    207 
    208 gfx::Size ViewEventTestBase::GetPreferredSize() {
    209   return gfx::Size();
    210 }
    211 
    212 void ViewEventTestBase::ScheduleMouseMoveInBackground(int x, int y) {
    213   if (!dnd_thread_.get()) {
    214     dnd_thread_.reset(new base::Thread("mouse-move-thread"));
    215     dnd_thread_->Start();
    216   }
    217   dnd_thread_->message_loop()->PostDelayedTask(
    218       FROM_HERE,
    219       base::Bind(base::IgnoreResult(&ui_controls::SendMouseMove), x, y),
    220       base::TimeDelta::FromMilliseconds(kMouseMoveDelayMS));
    221 }
    222 
    223 void ViewEventTestBase::StopBackgroundThread() {
    224   dnd_thread_.reset(NULL);
    225 }
    226 
    227 void ViewEventTestBase::RunTestMethod(const base::Closure& task) {
    228   StopBackgroundThread();
    229 
    230   task.Run();
    231   if (HasFatalFailure())
    232     Done();
    233 }
    234