view_event_test_base.h revision a3f7b4e666c476898878fa745f637129375cd889
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 26namespace aura { 27namespace test { 28class AuraTestHelper; 29} 30} 31 32namespace gfx { 33class 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 73class 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