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