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 #ifndef CHROME_TEST_BASE_VIEW_EVENT_TEST_BASE_H_
      6 #define CHROME_TEST_BASE_VIEW_EVENT_TEST_BASE_H_
      7 
      8 // We only want to use ViewEventTestBase in test targets which properly
      9 // isolate each test case by running each test in a separate process.
     10 // This way if a test hangs the test launcher can reliably terminate it.
     11 #if defined(HAS_OUT_OF_PROC_TEST_RUNNER)
     12 
     13 #include "base/bind.h"
     14 #include "base/callback.h"
     15 #include "base/compiler_specific.h"
     16 #include "base/message_loop/message_loop.h"
     17 #include "base/threading/thread.h"
     18 #include "content/public/test/test_browser_thread_bundle.h"
     19 #include "testing/gtest/include/gtest/gtest.h"
     20 #include "ui/views/widget/widget_delegate.h"
     21 
     22 #if defined(OS_WIN)
     23 #include "ui/base/win/scoped_ole_initializer.h"
     24 #endif
     25 
     26 namespace aura {
     27 namespace test {
     28 class AuraTestHelper;
     29 }
     30 }
     31 
     32 namespace gfx {
     33 class Size;
     34 }
     35 
     36 // Base class for Views based tests that dispatch events.
     37 //
     38 // As views based event test involves waiting for events to be processed,
     39 // writing a views based test is slightly different than that of writing
     40 // other unit tests. In particular when the test fails or is done you need
     41 // to stop the message loop. This can be done by way of invoking the Done
     42 // method.
     43 //
     44 // Any delayed callbacks should be done by way of CreateEventTask.
     45 // CreateEventTask checks to see if ASSERT_XXX has been invoked after invoking
     46 // the task. If there was a failure Done is invoked and the test stops.
     47 //
     48 // ViewEventTestBase creates a Window with the View returned from
     49 // CreateContentsView. The preferred size for the view can be customized by
     50 // overriding GetPreferredSize. If you do not override GetPreferredSize the
     51 // preferred size of the view returned from CreateContentsView is used.
     52 //
     53 // Subclasses of ViewEventTestBase must implement two methods:
     54 // . DoTestOnMessageLoop: invoked when the message loop is running. Run your
     55 //   test here, invoke Done when done.
     56 // . CreateContentsView: returns the view to place in the window.
     57 //
     58 // Once you have created a ViewEventTestBase use the macro VIEW_TEST to define
     59 // the fixture.
     60 //
     61 // I encountered weird timing problems in initiating dragging and drop that
     62 // necessitated ugly hacks. In particular when the hook installed by
     63 // ui_controls received the mouse event and posted a task that task was not
     64 // processed. To work around this use the following pattern when initiating
     65 // dnd:
     66 //   // Schedule the mouse move at a location slightly different from where
     67 //   // you really want to move to.
     68 //   ui_controls::SendMouseMoveNotifyWhenDone(loc.x + 10, loc.y,
     69 //       base::Bind(&YYY, this));
     70 //   // Then use this to schedule another mouse move.
     71 //   ScheduleMouseMoveInBackground(loc.x, loc.y);
     72 
     73 class ViewEventTestBase : public views::WidgetDelegate,
     74                           public testing::Test {
     75  public:
     76   ViewEventTestBase();
     77 
     78   // Invoke when done either because of failure or success. Quits the message
     79   // loop.
     80   void Done();
     81 
     82   // Creates a window.
     83   virtual void SetUp() OVERRIDE;
     84 
     85   // Destroys the window.
     86   virtual void TearDown() OVERRIDE;
     87 
     88   // Overridden from views::WidgetDelegate:
     89   virtual bool CanResize() const OVERRIDE;
     90   virtual views::View* GetContentsView() OVERRIDE;
     91   virtual const views::Widget* GetWidget() const OVERRIDE;
     92   virtual views::Widget* GetWidget() OVERRIDE;
     93 
     94   // Overridden to do nothing so that this class can be used in runnable tasks.
     95   void AddRef() {}
     96   void Release() {}
     97 
     98  protected:
     99   virtual ~ViewEventTestBase();
    100 
    101   // Returns the view that is added to the window.
    102   virtual views::View* CreateContentsView() = 0;
    103 
    104   // Called once the message loop is running.
    105   virtual void DoTestOnMessageLoop() = 0;
    106 
    107   // Invoke from test main. Shows the window, starts the message loop and
    108   // schedules a task that invokes DoTestOnMessageLoop.
    109   void StartMessageLoopAndRunTest();
    110 
    111   // Returns an empty Size. Subclasses that want a preferred size other than
    112   // that of the View returned by CreateContentsView should override this
    113   // appropriately.
    114   virtual gfx::Size GetPreferredSize();
    115 
    116   // Creates a task that calls the specified method back. The specified
    117   // method is called in such a way that if there are any test failures
    118   // Done is invoked.
    119   template <class T, class Method>
    120   base::Closure CreateEventTask(T* target, Method method) {
    121     return base::Bind(&ViewEventTestBase::RunTestMethod, this,
    122                       base::Bind(method, target));
    123   }
    124 
    125   // Spawns a new thread posts a MouseMove in the background.
    126   void ScheduleMouseMoveInBackground(int x, int y);
    127 
    128   views::Widget* window_;
    129 
    130  private:
    131   // Stops the thread started by ScheduleMouseMoveInBackground.
    132   void StopBackgroundThread();
    133 
    134   // Callback from CreateEventTask. Stops the background thread, runs the
    135   // supplied task and if there are failures invokes Done.
    136   void RunTestMethod(const base::Closure& task);
    137 
    138   // The content of the Window.
    139   views::View* content_view_;
    140 
    141   // Thread for posting background MouseMoves.
    142   scoped_ptr<base::Thread> dnd_thread_;
    143 
    144   content::TestBrowserThreadBundle thread_bundle_;
    145 
    146 #if defined(OS_WIN)
    147   ui::ScopedOleInitializer ole_initializer_;
    148 #endif
    149 
    150 #if defined(USE_AURA)
    151   scoped_ptr<aura::test::AuraTestHelper> aura_test_helper_;
    152 #endif
    153 
    154   DISALLOW_COPY_AND_ASSIGN(ViewEventTestBase);
    155 };
    156 
    157 // Convenience macro for defining a ViewEventTestBase. See class description
    158 // of ViewEventTestBase for details.
    159 #define VIEW_TEST(test_class, name) \
    160   TEST_F(test_class, name) {\
    161     StartMessageLoopAndRunTest();\
    162   }
    163 
    164 #endif  // defined(HAS_OUT_OF_PROC_TEST_RUNNER)
    165 
    166 #endif  // CHROME_TEST_BASE_VIEW_EVENT_TEST_BASE_H_
    167