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