Update metrics verification for dev-proxy.
[chromium-blink-merge.git] / ui / message_center / views / message_popup_collection_unittest.cc
blob551e4dd3357e125c4aecbff86d70bb2268a02cff
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/desktop_popup_alignment_delegate.h"
19 #include "ui/message_center/views/toast_contents_view.h"
20 #include "ui/views/test/views_test_base.h"
21 #include "ui/views/widget/widget.h"
22 #include "ui/views/widget/widget_delegate.h"
24 namespace message_center {
25 namespace test {
27 class MessagePopupCollectionTest : public views::ViewsTestBase {
28 public:
29 virtual void SetUp() OVERRIDE {
30 views::ViewsTestBase::SetUp();
31 MessageCenter::Initialize();
32 MessageCenter::Get()->DisableTimersForTest();
33 alignment_delegate_.reset(new DesktopPopupAlignmentDelegate);
34 collection_.reset(new MessagePopupCollection(
35 GetContext(), MessageCenter::Get(), NULL, alignment_delegate_.get()));
36 // This size fits test machines resolution and also can keep a few toasts
37 // w/o ill effects of hitting the screen overflow. This allows us to assume
38 // and verify normal layout of the toast stack.
39 SetDisplayInfo(gfx::Rect(0, 0, 600, 390), // taskbar at the bottom.
40 gfx::Rect(0, 0, 600, 400));
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 void SetDisplayInfo(const gfx::Rect& work_area,
72 const gfx::Rect& display_bounds) {
73 gfx::Display dummy_display;
74 dummy_display.set_bounds(display_bounds);
75 dummy_display.set_work_area(work_area);
76 alignment_delegate_->RecomputeAlignment(dummy_display);
77 PrepareForWait();
80 gfx::Rect GetWorkArea() {
81 return alignment_delegate_->work_area_;
84 ToastContentsView* GetToast(const std::string& id) {
85 for (MessagePopupCollection::Toasts::iterator iter =
86 collection_->toasts_.begin();
87 iter != collection_->toasts_.end(); ++iter) {
88 if ((*iter)->id() == id)
89 return *iter;
91 return NULL;
94 std::string AddNotification() {
95 std::string id = base::IntToString(id_++);
96 scoped_ptr<Notification> notification(
97 new Notification(NOTIFICATION_TYPE_BASE_FORMAT,
98 id,
99 base::UTF8ToUTF16("test title"),
100 base::UTF8ToUTF16("test message"),
101 gfx::Image(),
102 base::string16() /* display_source */,
103 NotifierId(),
104 message_center::RichNotificationData(),
105 NULL /* delegate */));
106 MessageCenter::Get()->AddNotification(notification.Pass());
107 return id;
110 void PrepareForWait() { collection_->CreateRunLoopForTest(); }
112 // Assumes there is non-zero pending work.
113 void WaitForTransitionsDone() {
114 collection_->WaitForTest();
115 collection_->CreateRunLoopForTest();
118 void CloseAllToasts() {
119 // Assumes there is at least one toast to close.
120 EXPECT_TRUE(GetToastCounts() > 0);
121 MessageCenter::Get()->RemoveAllNotifications(false);
124 gfx::Rect GetToastRectAt(size_t index) {
125 return collection_->GetToastRectAt(index);
128 private:
129 scoped_ptr<MessagePopupCollection> collection_;
130 scoped_ptr<DesktopPopupAlignmentDelegate> alignment_delegate_;
131 int id_;
134 TEST_F(MessagePopupCollectionTest, DismissOnClick) {
136 std::string id1 = AddNotification();
137 std::string id2 = AddNotification();
138 WaitForTransitionsDone();
140 EXPECT_EQ(2u, GetToastCounts());
141 EXPECT_TRUE(IsToastShown(id1));
142 EXPECT_TRUE(IsToastShown(id2));
144 MessageCenter::Get()->ClickOnNotification(id2);
145 WaitForTransitionsDone();
147 EXPECT_EQ(1u, GetToastCounts());
148 EXPECT_TRUE(IsToastShown(id1));
149 EXPECT_FALSE(IsToastShown(id2));
151 MessageCenter::Get()->ClickOnNotificationButton(id1, 0);
152 WaitForTransitionsDone();
153 EXPECT_EQ(0u, GetToastCounts());
154 EXPECT_FALSE(IsToastShown(id1));
155 EXPECT_FALSE(IsToastShown(id2));
158 TEST_F(MessagePopupCollectionTest, ShutdownDuringShowing) {
159 std::string id1 = AddNotification();
160 std::string id2 = AddNotification();
161 WaitForTransitionsDone();
162 EXPECT_EQ(2u, GetToastCounts());
163 EXPECT_TRUE(IsToastShown(id1));
164 EXPECT_TRUE(IsToastShown(id2));
166 // Finish without cleanup of notifications, which may cause use-after-free.
167 // See crbug.com/236448
168 GetWidget(id1)->CloseNow();
169 collection()->OnMouseExited(GetToast(id2));
172 TEST_F(MessagePopupCollectionTest, DefaultPositioning) {
173 std::string id0 = AddNotification();
174 std::string id1 = AddNotification();
175 std::string id2 = AddNotification();
176 std::string id3 = AddNotification();
177 WaitForTransitionsDone();
179 gfx::Rect r0 = GetToastRectAt(0);
180 gfx::Rect r1 = GetToastRectAt(1);
181 gfx::Rect r2 = GetToastRectAt(2);
182 gfx::Rect r3 = GetToastRectAt(3);
184 // 3 toasts are shown, equal size, vertical stack.
185 EXPECT_TRUE(IsToastShown(id0));
186 EXPECT_TRUE(IsToastShown(id1));
187 EXPECT_TRUE(IsToastShown(id2));
189 EXPECT_EQ(r0.width(), r1.width());
190 EXPECT_EQ(r1.width(), r2.width());
192 EXPECT_EQ(r0.height(), r1.height());
193 EXPECT_EQ(r1.height(), r2.height());
195 EXPECT_GT(r0.y(), r1.y());
196 EXPECT_GT(r1.y(), r2.y());
198 EXPECT_EQ(r0.x(), r1.x());
199 EXPECT_EQ(r1.x(), r2.x());
201 // The 4th toast is not shown yet.
202 EXPECT_FALSE(IsToastShown(id3));
203 EXPECT_EQ(0, r3.width());
204 EXPECT_EQ(0, r3.height());
206 CloseAllToasts();
207 EXPECT_EQ(0u, GetToastCounts());
210 TEST_F(MessagePopupCollectionTest, DefaultPositioningWithRightTaskbar) {
211 // If taskbar is on the right we show the toasts bottom to top as usual.
213 // Simulate a taskbar at the right.
214 SetDisplayInfo(gfx::Rect(0, 0, 590, 400), // Work-area.
215 gfx::Rect(0, 0, 600, 400)); // Display-bounds.
216 std::string id0 = AddNotification();
217 std::string id1 = AddNotification();
218 WaitForTransitionsDone();
220 gfx::Rect r0 = GetToastRectAt(0);
221 gfx::Rect r1 = GetToastRectAt(1);
223 // 2 toasts are shown, equal size, vertical stack.
224 EXPECT_TRUE(IsToastShown(id0));
225 EXPECT_TRUE(IsToastShown(id1));
227 EXPECT_EQ(r0.width(), r1.width());
228 EXPECT_EQ(r0.height(), r1.height());
229 EXPECT_GT(r0.y(), r1.y());
230 EXPECT_EQ(r0.x(), r1.x());
232 CloseAllToasts();
233 EXPECT_EQ(0u, GetToastCounts());
235 // Restore simulated taskbar position to bottom.
236 SetDisplayInfo(gfx::Rect(0, 0, 600, 390), // Work-area.
237 gfx::Rect(0, 0, 600, 400)); // Display-bounds.
240 TEST_F(MessagePopupCollectionTest, TopDownPositioningWithTopTaskbar) {
241 // Simulate a taskbar at the top.
242 SetDisplayInfo(gfx::Rect(0, 10, 600, 390), // Work-area.
243 gfx::Rect(0, 0, 600, 400)); // Display-bounds.
244 std::string id0 = AddNotification();
245 std::string id1 = AddNotification();
246 WaitForTransitionsDone();
248 gfx::Rect r0 = GetToastRectAt(0);
249 gfx::Rect r1 = GetToastRectAt(1);
251 // 2 toasts are shown, equal size, vertical stack.
252 EXPECT_TRUE(IsToastShown(id0));
253 EXPECT_TRUE(IsToastShown(id1));
255 EXPECT_EQ(r0.width(), r1.width());
256 EXPECT_EQ(r0.height(), r1.height());
257 EXPECT_LT(r0.y(), r1.y());
258 EXPECT_EQ(r0.x(), r1.x());
260 CloseAllToasts();
261 EXPECT_EQ(0u, GetToastCounts());
263 // Restore simulated taskbar position to bottom.
264 SetDisplayInfo(gfx::Rect(0, 0, 600, 390), // Work-area.
265 gfx::Rect(0, 0, 600, 400)); // Display-bounds.
268 TEST_F(MessagePopupCollectionTest, TopDownPositioningWithLeftAndTopTaskbar) {
269 // If there "seems" to be a taskbar on left and top (like in Unity), it is
270 // assumed that the actual taskbar is the top one.
272 // Simulate a taskbar at the top and left.
273 SetDisplayInfo(gfx::Rect(10, 10, 590, 390), // Work-area.
274 gfx::Rect(0, 0, 600, 400)); // Display-bounds.
275 std::string id0 = AddNotification();
276 std::string id1 = AddNotification();
277 WaitForTransitionsDone();
279 gfx::Rect r0 = GetToastRectAt(0);
280 gfx::Rect r1 = GetToastRectAt(1);
282 // 2 toasts are shown, equal size, vertical stack.
283 EXPECT_TRUE(IsToastShown(id0));
284 EXPECT_TRUE(IsToastShown(id1));
286 EXPECT_EQ(r0.width(), r1.width());
287 EXPECT_EQ(r0.height(), r1.height());
288 EXPECT_LT(r0.y(), r1.y());
289 EXPECT_EQ(r0.x(), r1.x());
291 CloseAllToasts();
292 EXPECT_EQ(0u, GetToastCounts());
294 // Restore simulated taskbar position to bottom.
295 SetDisplayInfo(gfx::Rect(0, 0, 600, 390), // Work-area.
296 gfx::Rect(0, 0, 600, 400)); // Display-bounds.
299 TEST_F(MessagePopupCollectionTest, TopDownPositioningWithBottomAndTopTaskbar) {
300 // If there "seems" to be a taskbar on bottom and top (like in Gnome), it is
301 // assumed that the actual taskbar is the top one.
303 // Simulate a taskbar at the top and bottom.
304 SetDisplayInfo(gfx::Rect(0, 10, 580, 400), // Work-area.
305 gfx::Rect(0, 0, 600, 400)); // Display-bounds.
306 std::string id0 = AddNotification();
307 std::string id1 = AddNotification();
308 WaitForTransitionsDone();
310 gfx::Rect r0 = GetToastRectAt(0);
311 gfx::Rect r1 = GetToastRectAt(1);
313 // 2 toasts are shown, equal size, vertical stack.
314 EXPECT_TRUE(IsToastShown(id0));
315 EXPECT_TRUE(IsToastShown(id1));
317 EXPECT_EQ(r0.width(), r1.width());
318 EXPECT_EQ(r0.height(), r1.height());
319 EXPECT_LT(r0.y(), r1.y());
320 EXPECT_EQ(r0.x(), r1.x());
322 CloseAllToasts();
323 EXPECT_EQ(0u, GetToastCounts());
325 // Restore simulated taskbar position to bottom.
326 SetDisplayInfo(gfx::Rect(0, 0, 600, 390), // Work-area.
327 gfx::Rect(0, 0, 600, 400)); // Display-bounds.
330 TEST_F(MessagePopupCollectionTest, LeftPositioningWithLeftTaskbar) {
331 // Simulate a taskbar at the left.
332 SetDisplayInfo(gfx::Rect(10, 0, 590, 400), // Work-area.
333 gfx::Rect(0, 0, 600, 400)); // Display-bounds.
334 std::string id0 = AddNotification();
335 std::string id1 = AddNotification();
336 WaitForTransitionsDone();
338 gfx::Rect r0 = GetToastRectAt(0);
339 gfx::Rect r1 = GetToastRectAt(1);
341 // 2 toasts are shown, equal size, vertical stack.
342 EXPECT_TRUE(IsToastShown(id0));
343 EXPECT_TRUE(IsToastShown(id1));
345 EXPECT_EQ(r0.width(), r1.width());
346 EXPECT_EQ(r0.height(), r1.height());
347 EXPECT_GT(r0.y(), r1.y());
348 EXPECT_EQ(r0.x(), r1.x());
350 // Ensure that toasts are on the left.
351 EXPECT_LT(r1.x(), GetWorkArea().CenterPoint().x());
353 CloseAllToasts();
354 EXPECT_EQ(0u, GetToastCounts());
356 // Restore simulated taskbar position to bottom.
357 SetDisplayInfo(gfx::Rect(0, 0, 600, 390), // Work-area.
358 gfx::Rect(0, 0, 600, 400)); // Display-bounds.
361 TEST_F(MessagePopupCollectionTest, DetectMouseHover) {
362 std::string id0 = AddNotification();
363 std::string id1 = AddNotification();
364 WaitForTransitionsDone();
366 views::WidgetDelegateView* toast0 = GetToast(id0);
367 EXPECT_TRUE(toast0 != NULL);
368 views::WidgetDelegateView* toast1 = GetToast(id1);
369 EXPECT_TRUE(toast1 != NULL);
371 ui::MouseEvent event(ui::ET_MOUSE_MOVED, gfx::Point(), gfx::Point(), 0, 0);
373 // Test that mouse detection logic works in presence of out-of-order events.
374 toast0->OnMouseEntered(event);
375 EXPECT_TRUE(MouseInCollection());
376 toast1->OnMouseEntered(event);
377 EXPECT_TRUE(MouseInCollection());
378 toast0->OnMouseExited(event);
379 EXPECT_TRUE(MouseInCollection());
380 toast1->OnMouseExited(event);
381 EXPECT_FALSE(MouseInCollection());
383 // Test that mouse detection logic works in presence of WindowClosing events.
384 toast0->OnMouseEntered(event);
385 EXPECT_TRUE(MouseInCollection());
386 toast1->OnMouseEntered(event);
387 EXPECT_TRUE(MouseInCollection());
388 toast0->WindowClosing();
389 EXPECT_TRUE(MouseInCollection());
390 toast1->WindowClosing();
391 EXPECT_FALSE(MouseInCollection());
394 // TODO(dimich): Test repositioning - both normal one and when user is closing
395 // the toasts.
396 TEST_F(MessagePopupCollectionTest, DetectMouseHoverWithUserClose) {
397 std::string id0 = AddNotification();
398 std::string id1 = AddNotification();
399 WaitForTransitionsDone();
401 views::WidgetDelegateView* toast0 = GetToast(id0);
402 EXPECT_TRUE(toast0 != NULL);
403 views::WidgetDelegateView* toast1 = GetToast(id1);
404 ASSERT_TRUE(toast1 != NULL);
406 ui::MouseEvent event(ui::ET_MOUSE_MOVED, gfx::Point(), gfx::Point(), 0, 0);
407 toast1->OnMouseEntered(event);
408 static_cast<MessageCenterObserver*>(collection())->OnNotificationRemoved(
409 id1, true);
411 EXPECT_FALSE(MouseInCollection());
412 std::string id2 = AddNotification();
414 WaitForTransitionsDone();
415 views::WidgetDelegateView* toast2 = GetToast(id2);
416 EXPECT_TRUE(toast2 != NULL);
420 } // namespace test
421 } // namespace message_center