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