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