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