Update path of checkdeps to buildtools checkout
[chromium-blink-merge.git] / ui / message_center / views / message_popup_collection_unittest.cc
blobeacc68077263adf9e73f8e58f0795024562bdc8d
1 // Copyright (c) 2013 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.
5 #include "ui/message_center/views/message_popup_collection.h"
7 #include <list>
9 #include "base/message_loop/message_loop.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 #include "ui/events/event.h"
14 #include "ui/events/event_constants.h"
15 #include "ui/gfx/display.h"
16 #include "ui/gfx/rect.h"
17 #include "ui/message_center/fake_message_center.h"
18 #include "ui/message_center/views/toast_contents_view.h"
19 #include "ui/views/test/views_test_base.h"
20 #include "ui/views/widget/widget.h"
21 #include "ui/views/widget/widget_delegate.h"
23 namespace message_center {
24 namespace test {
26 class MessagePopupCollectionTest : public views::ViewsTestBase {
27 public:
28 virtual void SetUp() OVERRIDE {
29 views::ViewsTestBase::SetUp();
30 MessageCenter::Initialize();
31 MessageCenter::Get()->DisableTimersForTest();
32 collection_.reset(new MessagePopupCollection(
33 GetContext(), MessageCenter::Get(), NULL, false));
34 // This size fits test machines resolution and also can keep a few toasts
35 // w/o ill effects of hitting the screen overflow. This allows us to assume
36 // and verify normal layout of the toast stack.
37 collection_->SetDisplayInfo(gfx::Rect(0, 0, 600, 390),
38 gfx::Rect(0, 0, 600, 400)); // Simulate a
39 // taskbar at the
40 // bottom.
41 id_ = 0;
42 PrepareForWait();
45 virtual void TearDown() OVERRIDE {
46 collection_.reset();
47 MessageCenter::Shutdown();
48 views::ViewsTestBase::TearDown();
51 protected:
52 MessagePopupCollection* collection() { return collection_.get(); }
54 size_t GetToastCounts() {
55 return collection_->toasts_.size();
58 bool MouseInCollection() {
59 return collection_->latest_toast_entered_ != NULL;
62 bool IsToastShown(const std::string& id) {
63 views::Widget* widget = collection_->GetWidgetForTest(id);
64 return widget && widget->IsVisible();
67 views::Widget* GetWidget(const std::string& id) {
68 return collection_->GetWidgetForTest(id);
71 gfx::Rect GetWorkArea() {
72 return collection_->work_area_;
75 ToastContentsView* GetToast(const std::string& id) {
76 for (MessagePopupCollection::Toasts::iterator iter =
77 collection_->toasts_.begin();
78 iter != collection_->toasts_.end(); ++iter) {
79 if ((*iter)->id() == id)
80 return *iter;
82 return NULL;
85 std::string AddNotification() {
86 std::string id = base::IntToString(id_++);
87 scoped_ptr<Notification> notification(
88 new Notification(NOTIFICATION_TYPE_BASE_FORMAT,
89 id,
90 base::UTF8ToUTF16("test title"),
91 base::UTF8ToUTF16("test message"),
92 gfx::Image(),
93 base::string16() /* display_source */,
94 NotifierId(),
95 message_center::RichNotificationData(),
96 NULL /* delegate */));
97 MessageCenter::Get()->AddNotification(notification.Pass());
98 return id;
101 void PrepareForWait() { collection_->CreateRunLoopForTest(); }
103 // Assumes there is non-zero pending work.
104 void WaitForTransitionsDone() {
105 collection_->WaitForTest();
106 collection_->CreateRunLoopForTest();
109 void CloseAllToasts() {
110 // Assumes there is at least one toast to close.
111 EXPECT_TRUE(GetToastCounts() > 0);
112 MessageCenter::Get()->RemoveAllNotifications(false);
115 gfx::Rect GetToastRectAt(size_t index) {
116 return collection_->GetToastRectAt(index);
119 private:
120 scoped_ptr<MessagePopupCollection> collection_;
121 int id_;
124 TEST_F(MessagePopupCollectionTest, DismissOnClick) {
126 std::string id1 = AddNotification();
127 std::string id2 = AddNotification();
128 WaitForTransitionsDone();
130 EXPECT_EQ(2u, GetToastCounts());
131 EXPECT_TRUE(IsToastShown(id1));
132 EXPECT_TRUE(IsToastShown(id2));
134 MessageCenter::Get()->ClickOnNotification(id2);
135 WaitForTransitionsDone();
137 EXPECT_EQ(1u, GetToastCounts());
138 EXPECT_TRUE(IsToastShown(id1));
139 EXPECT_FALSE(IsToastShown(id2));
141 MessageCenter::Get()->ClickOnNotificationButton(id1, 0);
142 WaitForTransitionsDone();
143 EXPECT_EQ(0u, GetToastCounts());
144 EXPECT_FALSE(IsToastShown(id1));
145 EXPECT_FALSE(IsToastShown(id2));
148 TEST_F(MessagePopupCollectionTest, ShutdownDuringShowing) {
149 std::string id1 = AddNotification();
150 std::string id2 = AddNotification();
151 WaitForTransitionsDone();
152 EXPECT_EQ(2u, GetToastCounts());
153 EXPECT_TRUE(IsToastShown(id1));
154 EXPECT_TRUE(IsToastShown(id2));
156 // Finish without cleanup of notifications, which may cause use-after-free.
157 // See crbug.com/236448
158 GetWidget(id1)->CloseNow();
159 collection()->OnMouseExited(GetToast(id2));
162 TEST_F(MessagePopupCollectionTest, DefaultPositioning) {
163 std::string id0 = AddNotification();
164 std::string id1 = AddNotification();
165 std::string id2 = AddNotification();
166 std::string id3 = AddNotification();
167 WaitForTransitionsDone();
169 gfx::Rect r0 = GetToastRectAt(0);
170 gfx::Rect r1 = GetToastRectAt(1);
171 gfx::Rect r2 = GetToastRectAt(2);
172 gfx::Rect r3 = GetToastRectAt(3);
174 // 3 toasts are shown, equal size, vertical stack.
175 EXPECT_TRUE(IsToastShown(id0));
176 EXPECT_TRUE(IsToastShown(id1));
177 EXPECT_TRUE(IsToastShown(id2));
179 EXPECT_EQ(r0.width(), r1.width());
180 EXPECT_EQ(r1.width(), r2.width());
182 EXPECT_EQ(r0.height(), r1.height());
183 EXPECT_EQ(r1.height(), r2.height());
185 EXPECT_GT(r0.y(), r1.y());
186 EXPECT_GT(r1.y(), r2.y());
188 EXPECT_EQ(r0.x(), r1.x());
189 EXPECT_EQ(r1.x(), r2.x());
191 // The 4th toast is not shown yet.
192 EXPECT_FALSE(IsToastShown(id3));
193 EXPECT_EQ(0, r3.width());
194 EXPECT_EQ(0, r3.height());
196 CloseAllToasts();
197 EXPECT_EQ(0u, GetToastCounts());
200 TEST_F(MessagePopupCollectionTest, DefaultPositioningWithRightTaskbar) {
201 // If taskbar is on the right we show the toasts bottom to top as usual.
203 // Simulate a taskbar at the right.
204 collection()->SetDisplayInfo(gfx::Rect(0, 0, 590, 400), // Work-area.
205 gfx::Rect(0, 0, 600, 400)); // Display-bounds.
206 std::string id0 = AddNotification();
207 std::string id1 = AddNotification();
208 WaitForTransitionsDone();
210 gfx::Rect r0 = GetToastRectAt(0);
211 gfx::Rect r1 = GetToastRectAt(1);
213 // 2 toasts are shown, equal size, vertical stack.
214 EXPECT_TRUE(IsToastShown(id0));
215 EXPECT_TRUE(IsToastShown(id1));
217 EXPECT_EQ(r0.width(), r1.width());
218 EXPECT_EQ(r0.height(), r1.height());
219 EXPECT_GT(r0.y(), r1.y());
220 EXPECT_EQ(r0.x(), r1.x());
222 CloseAllToasts();
223 EXPECT_EQ(0u, GetToastCounts());
225 // Restore simulated taskbar position to bottom.
226 collection()->SetDisplayInfo(gfx::Rect(0, 0, 600, 390), // Work-area.
227 gfx::Rect(0, 0, 600, 400)); // Display-bounds.
230 TEST_F(MessagePopupCollectionTest, TopDownPositioningWithTopTaskbar) {
231 // Simulate a taskbar at the top.
232 collection()->SetDisplayInfo(gfx::Rect(0, 10, 600, 390), // Work-area.
233 gfx::Rect(0, 0, 600, 400)); // Display-bounds.
234 std::string id0 = AddNotification();
235 std::string id1 = AddNotification();
236 WaitForTransitionsDone();
238 gfx::Rect r0 = GetToastRectAt(0);
239 gfx::Rect r1 = GetToastRectAt(1);
241 // 2 toasts are shown, equal size, vertical stack.
242 EXPECT_TRUE(IsToastShown(id0));
243 EXPECT_TRUE(IsToastShown(id1));
245 EXPECT_EQ(r0.width(), r1.width());
246 EXPECT_EQ(r0.height(), r1.height());
247 EXPECT_LT(r0.y(), r1.y());
248 EXPECT_EQ(r0.x(), r1.x());
250 CloseAllToasts();
251 EXPECT_EQ(0u, GetToastCounts());
253 // Restore simulated taskbar position to bottom.
254 collection()->SetDisplayInfo(gfx::Rect(0, 0, 600, 390), // Work-area.
255 gfx::Rect(0, 0, 600, 400)); // Display-bounds.
258 TEST_F(MessagePopupCollectionTest, TopDownPositioningWithLeftAndTopTaskbar) {
259 // If there "seems" to be a taskbar on left and top (like in Unity), it is
260 // assumed that the actual taskbar is the top one.
262 // Simulate a taskbar at the top and left.
263 collection()->SetDisplayInfo(gfx::Rect(10, 10, 590, 390), // Work-area.
264 gfx::Rect(0, 0, 600, 400)); // Display-bounds.
265 std::string id0 = AddNotification();
266 std::string id1 = AddNotification();
267 WaitForTransitionsDone();
269 gfx::Rect r0 = GetToastRectAt(0);
270 gfx::Rect r1 = GetToastRectAt(1);
272 // 2 toasts are shown, equal size, vertical stack.
273 EXPECT_TRUE(IsToastShown(id0));
274 EXPECT_TRUE(IsToastShown(id1));
276 EXPECT_EQ(r0.width(), r1.width());
277 EXPECT_EQ(r0.height(), r1.height());
278 EXPECT_LT(r0.y(), r1.y());
279 EXPECT_EQ(r0.x(), r1.x());
281 CloseAllToasts();
282 EXPECT_EQ(0u, GetToastCounts());
284 // Restore simulated taskbar position to bottom.
285 collection()->SetDisplayInfo(gfx::Rect(0, 0, 600, 390), // Work-area.
286 gfx::Rect(0, 0, 600, 400)); // Display-bounds.
289 TEST_F(MessagePopupCollectionTest, TopDownPositioningWithBottomAndTopTaskbar) {
290 // If there "seems" to be a taskbar on bottom and top (like in Gnome), it is
291 // assumed that the actual taskbar is the top one.
293 // Simulate a taskbar at the top and bottom.
294 collection()->SetDisplayInfo(gfx::Rect(0, 10, 580, 400), // Work-area.
295 gfx::Rect(0, 0, 600, 400)); // Display-bounds.
296 std::string id0 = AddNotification();
297 std::string id1 = AddNotification();
298 WaitForTransitionsDone();
300 gfx::Rect r0 = GetToastRectAt(0);
301 gfx::Rect r1 = GetToastRectAt(1);
303 // 2 toasts are shown, equal size, vertical stack.
304 EXPECT_TRUE(IsToastShown(id0));
305 EXPECT_TRUE(IsToastShown(id1));
307 EXPECT_EQ(r0.width(), r1.width());
308 EXPECT_EQ(r0.height(), r1.height());
309 EXPECT_LT(r0.y(), r1.y());
310 EXPECT_EQ(r0.x(), r1.x());
312 CloseAllToasts();
313 EXPECT_EQ(0u, GetToastCounts());
315 // Restore simulated taskbar position to bottom.
316 collection()->SetDisplayInfo(gfx::Rect(0, 0, 600, 390), // Work-area.
317 gfx::Rect(0, 0, 600, 400)); // Display-bounds.
320 TEST_F(MessagePopupCollectionTest, LeftPositioningWithLeftTaskbar) {
321 // Simulate a taskbar at the left.
322 collection()->SetDisplayInfo(gfx::Rect(10, 0, 590, 400), // Work-area.
323 gfx::Rect(0, 0, 600, 400)); // Display-bounds.
324 std::string id0 = AddNotification();
325 std::string id1 = AddNotification();
326 WaitForTransitionsDone();
328 gfx::Rect r0 = GetToastRectAt(0);
329 gfx::Rect r1 = GetToastRectAt(1);
331 // 2 toasts are shown, equal size, vertical stack.
332 EXPECT_TRUE(IsToastShown(id0));
333 EXPECT_TRUE(IsToastShown(id1));
335 EXPECT_EQ(r0.width(), r1.width());
336 EXPECT_EQ(r0.height(), r1.height());
337 EXPECT_GT(r0.y(), r1.y());
338 EXPECT_EQ(r0.x(), r1.x());
340 // Ensure that toasts are on the left.
341 EXPECT_LT(r1.x(), GetWorkArea().CenterPoint().x());
343 CloseAllToasts();
344 EXPECT_EQ(0u, GetToastCounts());
346 // Restore simulated taskbar position to bottom.
347 collection()->SetDisplayInfo(gfx::Rect(0, 0, 600, 390), // Work-area.
348 gfx::Rect(0, 0, 600, 400)); // Display-bounds.
351 TEST_F(MessagePopupCollectionTest, DetectMouseHover) {
352 std::string id0 = AddNotification();
353 std::string id1 = AddNotification();
354 WaitForTransitionsDone();
356 views::WidgetDelegateView* toast0 = GetToast(id0);
357 EXPECT_TRUE(toast0 != NULL);
358 views::WidgetDelegateView* toast1 = GetToast(id1);
359 EXPECT_TRUE(toast1 != NULL);
361 ui::MouseEvent event(ui::ET_MOUSE_MOVED, gfx::Point(), gfx::Point(), 0, 0);
363 // Test that mouse detection logic works in presence of out-of-order events.
364 toast0->OnMouseEntered(event);
365 EXPECT_TRUE(MouseInCollection());
366 toast1->OnMouseEntered(event);
367 EXPECT_TRUE(MouseInCollection());
368 toast0->OnMouseExited(event);
369 EXPECT_TRUE(MouseInCollection());
370 toast1->OnMouseExited(event);
371 EXPECT_FALSE(MouseInCollection());
373 // Test that mouse detection logic works in presence of WindowClosing events.
374 toast0->OnMouseEntered(event);
375 EXPECT_TRUE(MouseInCollection());
376 toast1->OnMouseEntered(event);
377 EXPECT_TRUE(MouseInCollection());
378 toast0->WindowClosing();
379 EXPECT_TRUE(MouseInCollection());
380 toast1->WindowClosing();
381 EXPECT_FALSE(MouseInCollection());
384 // TODO(dimich): Test repositioning - both normal one and when user is closing
385 // the toasts.
386 TEST_F(MessagePopupCollectionTest, DetectMouseHoverWithUserClose) {
387 std::string id0 = AddNotification();
388 std::string id1 = AddNotification();
389 WaitForTransitionsDone();
391 views::WidgetDelegateView* toast0 = GetToast(id0);
392 EXPECT_TRUE(toast0 != NULL);
393 views::WidgetDelegateView* toast1 = GetToast(id1);
394 ASSERT_TRUE(toast1 != NULL);
396 ui::MouseEvent event(ui::ET_MOUSE_MOVED, gfx::Point(), gfx::Point(), 0, 0);
397 toast1->OnMouseEntered(event);
398 static_cast<MessageCenterObserver*>(collection())->OnNotificationRemoved(
399 id1, true);
401 EXPECT_FALSE(MouseInCollection());
402 std::string id2 = AddNotification();
404 WaitForTransitionsDone();
405 views::WidgetDelegateView* toast2 = GetToast(id2);
406 EXPECT_TRUE(toast2 != NULL);
410 } // namespace test
411 } // namespace message_center