Add ICU message format support
[chromium-blink-merge.git] / ui / message_center / views / message_popup_collection_unittest.cc
blob74934dd59a4111ce06918e9c3345d15df8416850
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/events/event_utils.h"
16 #include "ui/gfx/display.h"
17 #include "ui/gfx/geometry/rect.h"
18 #include "ui/message_center/fake_message_center.h"
19 #include "ui/message_center/views/desktop_popup_alignment_delegate.h"
20 #include "ui/message_center/views/toast_contents_view.h"
21 #include "ui/views/test/views_test_base.h"
22 #include "ui/views/widget/widget.h"
23 #include "ui/views/widget/widget_delegate.h"
25 namespace message_center {
26 namespace test {
28 class MessagePopupCollectionTest : public views::ViewsTestBase {
29 public:
30 void SetUp() override {
31 views::ViewsTestBase::SetUp();
32 MessageCenter::Initialize();
33 MessageCenter::Get()->DisableTimersForTest();
34 alignment_delegate_.reset(new DesktopPopupAlignmentDelegate);
35 collection_.reset(new MessagePopupCollection(
36 GetContext(), MessageCenter::Get(), NULL, alignment_delegate_.get()));
37 // This size fits test machines resolution and also can keep a few toasts
38 // w/o ill effects of hitting the screen overflow. This allows us to assume
39 // and verify normal layout of the toast stack.
40 SetDisplayInfo(gfx::Rect(0, 0, 600, 390), // taskbar at the bottom.
41 gfx::Rect(0, 0, 600, 400));
42 id_ = 0;
43 PrepareForWait();
46 void TearDown() override {
47 collection_.reset();
48 MessageCenter::Shutdown();
49 views::ViewsTestBase::TearDown();
52 protected:
53 MessagePopupCollection* collection() { return collection_.get(); }
55 size_t GetToastCounts() {
56 return collection_->toasts_.size();
59 bool MouseInCollection() {
60 return collection_->latest_toast_entered_ != NULL;
63 bool IsToastShown(const std::string& id) {
64 views::Widget* widget = collection_->GetWidgetForTest(id);
65 return widget && widget->IsVisible();
68 views::Widget* GetWidget(const std::string& id) {
69 return collection_->GetWidgetForTest(id);
72 void SetDisplayInfo(const gfx::Rect& work_area,
73 const gfx::Rect& display_bounds) {
74 gfx::Display dummy_display;
75 dummy_display.set_bounds(display_bounds);
76 dummy_display.set_work_area(work_area);
77 alignment_delegate_->RecomputeAlignment(dummy_display);
78 PrepareForWait();
81 gfx::Rect GetWorkArea() {
82 return alignment_delegate_->work_area_;
85 ToastContentsView* GetToast(const std::string& id) {
86 for (MessagePopupCollection::Toasts::iterator iter =
87 collection_->toasts_.begin();
88 iter != collection_->toasts_.end(); ++iter) {
89 if ((*iter)->id() == id)
90 return *iter;
92 return NULL;
95 std::string AddNotification() {
96 std::string id = base::IntToString(id_++);
97 scoped_ptr<Notification> notification(
98 new Notification(NOTIFICATION_TYPE_BASE_FORMAT,
99 id,
100 base::UTF8ToUTF16("test title"),
101 base::UTF8ToUTF16("test message"),
102 gfx::Image(),
103 base::string16() /* display_source */,
104 NotifierId(),
105 message_center::RichNotificationData(),
106 NULL /* delegate */));
107 MessageCenter::Get()->AddNotification(notification.Pass());
108 return id;
111 void PrepareForWait() { collection_->CreateRunLoopForTest(); }
113 // Assumes there is non-zero pending work.
114 void WaitForTransitionsDone() {
115 collection_->WaitForTest();
116 collection_->CreateRunLoopForTest();
119 void CloseAllToasts() {
120 // Assumes there is at least one toast to close.
121 EXPECT_TRUE(GetToastCounts() > 0);
122 MessageCenter::Get()->RemoveAllNotifications(false);
125 gfx::Rect GetToastRectAt(size_t index) {
126 return collection_->GetToastRectAt(index);
129 private:
130 scoped_ptr<MessagePopupCollection> collection_;
131 scoped_ptr<DesktopPopupAlignmentDelegate> alignment_delegate_;
132 int id_;
135 TEST_F(MessagePopupCollectionTest, DismissOnClick) {
137 std::string id1 = AddNotification();
138 std::string id2 = AddNotification();
139 WaitForTransitionsDone();
141 EXPECT_EQ(2u, GetToastCounts());
142 EXPECT_TRUE(IsToastShown(id1));
143 EXPECT_TRUE(IsToastShown(id2));
145 MessageCenter::Get()->ClickOnNotification(id2);
146 WaitForTransitionsDone();
148 EXPECT_EQ(1u, GetToastCounts());
149 EXPECT_TRUE(IsToastShown(id1));
150 EXPECT_FALSE(IsToastShown(id2));
152 MessageCenter::Get()->ClickOnNotificationButton(id1, 0);
153 WaitForTransitionsDone();
154 EXPECT_EQ(0u, GetToastCounts());
155 EXPECT_FALSE(IsToastShown(id1));
156 EXPECT_FALSE(IsToastShown(id2));
159 TEST_F(MessagePopupCollectionTest, ShutdownDuringShowing) {
160 std::string id1 = AddNotification();
161 std::string id2 = AddNotification();
162 WaitForTransitionsDone();
163 EXPECT_EQ(2u, GetToastCounts());
164 EXPECT_TRUE(IsToastShown(id1));
165 EXPECT_TRUE(IsToastShown(id2));
167 // Finish without cleanup of notifications, which may cause use-after-free.
168 // See crbug.com/236448
169 GetWidget(id1)->CloseNow();
170 collection()->OnMouseExited(GetToast(id2));
172 GetWidget(id2)->CloseNow();
175 TEST_F(MessagePopupCollectionTest, DefaultPositioning) {
176 std::string id0 = AddNotification();
177 std::string id1 = AddNotification();
178 std::string id2 = AddNotification();
179 std::string id3 = AddNotification();
180 WaitForTransitionsDone();
182 gfx::Rect r0 = GetToastRectAt(0);
183 gfx::Rect r1 = GetToastRectAt(1);
184 gfx::Rect r2 = GetToastRectAt(2);
185 gfx::Rect r3 = GetToastRectAt(3);
187 // 3 toasts are shown, equal size, vertical stack.
188 EXPECT_TRUE(IsToastShown(id0));
189 EXPECT_TRUE(IsToastShown(id1));
190 EXPECT_TRUE(IsToastShown(id2));
192 EXPECT_EQ(r0.width(), r1.width());
193 EXPECT_EQ(r1.width(), r2.width());
195 EXPECT_EQ(r0.height(), r1.height());
196 EXPECT_EQ(r1.height(), r2.height());
198 EXPECT_GT(r0.y(), r1.y());
199 EXPECT_GT(r1.y(), r2.y());
201 EXPECT_EQ(r0.x(), r1.x());
202 EXPECT_EQ(r1.x(), r2.x());
204 // The 4th toast is not shown yet.
205 EXPECT_FALSE(IsToastShown(id3));
206 EXPECT_EQ(0, r3.width());
207 EXPECT_EQ(0, r3.height());
209 CloseAllToasts();
210 EXPECT_EQ(0u, GetToastCounts());
211 WaitForTransitionsDone();
214 TEST_F(MessagePopupCollectionTest, DefaultPositioningWithRightTaskbar) {
215 // If taskbar is on the right we show the toasts bottom to top as usual.
217 // Simulate a taskbar at the right.
218 SetDisplayInfo(gfx::Rect(0, 0, 590, 400), // Work-area.
219 gfx::Rect(0, 0, 600, 400)); // Display-bounds.
220 std::string id0 = AddNotification();
221 std::string id1 = AddNotification();
222 WaitForTransitionsDone();
224 gfx::Rect r0 = GetToastRectAt(0);
225 gfx::Rect r1 = GetToastRectAt(1);
227 // 2 toasts are shown, equal size, vertical stack.
228 EXPECT_TRUE(IsToastShown(id0));
229 EXPECT_TRUE(IsToastShown(id1));
231 EXPECT_EQ(r0.width(), r1.width());
232 EXPECT_EQ(r0.height(), r1.height());
233 EXPECT_GT(r0.y(), r1.y());
234 EXPECT_EQ(r0.x(), r1.x());
236 CloseAllToasts();
237 EXPECT_EQ(0u, GetToastCounts());
239 // Restore simulated taskbar position to bottom.
240 SetDisplayInfo(gfx::Rect(0, 0, 600, 390), // Work-area.
241 gfx::Rect(0, 0, 600, 400)); // Display-bounds.
243 WaitForTransitionsDone();
246 TEST_F(MessagePopupCollectionTest, TopDownPositioningWithTopTaskbar) {
247 // Simulate a taskbar at the top.
248 SetDisplayInfo(gfx::Rect(0, 10, 600, 390), // Work-area.
249 gfx::Rect(0, 0, 600, 400)); // Display-bounds.
250 std::string id0 = AddNotification();
251 std::string id1 = AddNotification();
252 WaitForTransitionsDone();
254 gfx::Rect r0 = GetToastRectAt(0);
255 gfx::Rect r1 = GetToastRectAt(1);
257 // 2 toasts are shown, equal size, vertical stack.
258 EXPECT_TRUE(IsToastShown(id0));
259 EXPECT_TRUE(IsToastShown(id1));
261 EXPECT_EQ(r0.width(), r1.width());
262 EXPECT_EQ(r0.height(), r1.height());
263 EXPECT_LT(r0.y(), r1.y());
264 EXPECT_EQ(r0.x(), r1.x());
266 CloseAllToasts();
267 EXPECT_EQ(0u, GetToastCounts());
268 WaitForTransitionsDone();
270 // Restore simulated taskbar position to bottom.
271 SetDisplayInfo(gfx::Rect(0, 0, 600, 390), // Work-area.
272 gfx::Rect(0, 0, 600, 400)); // Display-bounds.
275 TEST_F(MessagePopupCollectionTest, TopDownPositioningWithLeftAndTopTaskbar) {
276 // If there "seems" to be a taskbar on left and top (like in Unity), it is
277 // assumed that the actual taskbar is the top one.
279 // Simulate a taskbar at the top and left.
280 SetDisplayInfo(gfx::Rect(10, 10, 590, 390), // Work-area.
281 gfx::Rect(0, 0, 600, 400)); // Display-bounds.
282 std::string id0 = AddNotification();
283 std::string id1 = AddNotification();
284 WaitForTransitionsDone();
286 gfx::Rect r0 = GetToastRectAt(0);
287 gfx::Rect r1 = GetToastRectAt(1);
289 // 2 toasts are shown, equal size, vertical stack.
290 EXPECT_TRUE(IsToastShown(id0));
291 EXPECT_TRUE(IsToastShown(id1));
293 EXPECT_EQ(r0.width(), r1.width());
294 EXPECT_EQ(r0.height(), r1.height());
295 EXPECT_LT(r0.y(), r1.y());
296 EXPECT_EQ(r0.x(), r1.x());
298 CloseAllToasts();
299 EXPECT_EQ(0u, GetToastCounts());
300 WaitForTransitionsDone();
302 // Restore simulated taskbar position to bottom.
303 SetDisplayInfo(gfx::Rect(0, 0, 600, 390), // Work-area.
304 gfx::Rect(0, 0, 600, 400)); // Display-bounds.
307 TEST_F(MessagePopupCollectionTest, TopDownPositioningWithBottomAndTopTaskbar) {
308 // If there "seems" to be a taskbar on bottom and top (like in Gnome), it is
309 // assumed that the actual taskbar is the top one.
311 // Simulate a taskbar at the top and bottom.
312 SetDisplayInfo(gfx::Rect(0, 10, 580, 400), // Work-area.
313 gfx::Rect(0, 0, 600, 400)); // Display-bounds.
314 std::string id0 = AddNotification();
315 std::string id1 = AddNotification();
316 WaitForTransitionsDone();
318 gfx::Rect r0 = GetToastRectAt(0);
319 gfx::Rect r1 = GetToastRectAt(1);
321 // 2 toasts are shown, equal size, vertical stack.
322 EXPECT_TRUE(IsToastShown(id0));
323 EXPECT_TRUE(IsToastShown(id1));
325 EXPECT_EQ(r0.width(), r1.width());
326 EXPECT_EQ(r0.height(), r1.height());
327 EXPECT_LT(r0.y(), r1.y());
328 EXPECT_EQ(r0.x(), r1.x());
330 CloseAllToasts();
331 EXPECT_EQ(0u, GetToastCounts());
332 WaitForTransitionsDone();
334 // Restore simulated taskbar position to bottom.
335 SetDisplayInfo(gfx::Rect(0, 0, 600, 390), // Work-area.
336 gfx::Rect(0, 0, 600, 400)); // Display-bounds.
339 TEST_F(MessagePopupCollectionTest, LeftPositioningWithLeftTaskbar) {
340 // Simulate a taskbar at the left.
341 SetDisplayInfo(gfx::Rect(10, 0, 590, 400), // Work-area.
342 gfx::Rect(0, 0, 600, 400)); // Display-bounds.
343 std::string id0 = AddNotification();
344 std::string id1 = AddNotification();
345 WaitForTransitionsDone();
347 gfx::Rect r0 = GetToastRectAt(0);
348 gfx::Rect r1 = GetToastRectAt(1);
350 // 2 toasts are shown, equal size, vertical stack.
351 EXPECT_TRUE(IsToastShown(id0));
352 EXPECT_TRUE(IsToastShown(id1));
354 EXPECT_EQ(r0.width(), r1.width());
355 EXPECT_EQ(r0.height(), r1.height());
356 EXPECT_GT(r0.y(), r1.y());
357 EXPECT_EQ(r0.x(), r1.x());
359 // Ensure that toasts are on the left.
360 EXPECT_LT(r1.x(), GetWorkArea().CenterPoint().x());
362 CloseAllToasts();
363 EXPECT_EQ(0u, GetToastCounts());
364 WaitForTransitionsDone();
366 // Restore simulated taskbar position to bottom.
367 SetDisplayInfo(gfx::Rect(0, 0, 600, 390), // Work-area.
368 gfx::Rect(0, 0, 600, 400)); // Display-bounds.
371 TEST_F(MessagePopupCollectionTest, DetectMouseHover) {
372 std::string id0 = AddNotification();
373 std::string id1 = AddNotification();
374 WaitForTransitionsDone();
376 views::WidgetDelegateView* toast0 = GetToast(id0);
377 EXPECT_TRUE(toast0 != NULL);
378 views::WidgetDelegateView* toast1 = GetToast(id1);
379 EXPECT_TRUE(toast1 != NULL);
381 ui::MouseEvent event(ui::ET_MOUSE_MOVED, gfx::Point(), gfx::Point(),
382 ui::EventTimeForNow(), 0, 0);
384 // Test that mouse detection logic works in presence of out-of-order events.
385 toast0->OnMouseEntered(event);
386 EXPECT_TRUE(MouseInCollection());
387 toast1->OnMouseEntered(event);
388 EXPECT_TRUE(MouseInCollection());
389 toast0->OnMouseExited(event);
390 EXPECT_TRUE(MouseInCollection());
391 toast1->OnMouseExited(event);
392 EXPECT_FALSE(MouseInCollection());
394 // Test that mouse detection logic works in presence of WindowClosing events.
395 toast0->OnMouseEntered(event);
396 EXPECT_TRUE(MouseInCollection());
397 toast1->OnMouseEntered(event);
398 EXPECT_TRUE(MouseInCollection());
399 toast0->GetWidget()->CloseNow();
400 EXPECT_TRUE(MouseInCollection());
401 toast1->GetWidget()->CloseNow();
402 EXPECT_FALSE(MouseInCollection());
405 // TODO(dimich): Test repositioning - both normal one and when user is closing
406 // the toasts.
407 TEST_F(MessagePopupCollectionTest, DetectMouseHoverWithUserClose) {
408 std::string id0 = AddNotification();
409 std::string id1 = AddNotification();
410 WaitForTransitionsDone();
412 views::WidgetDelegateView* toast0 = GetToast(id0);
413 EXPECT_TRUE(toast0 != NULL);
414 views::WidgetDelegateView* toast1 = GetToast(id1);
415 ASSERT_TRUE(toast1 != NULL);
417 ui::MouseEvent event(ui::ET_MOUSE_MOVED, gfx::Point(), gfx::Point(),
418 ui::EventTimeForNow(), 0, 0);
419 toast1->OnMouseEntered(event);
420 static_cast<MessageCenterObserver*>(collection())->OnNotificationRemoved(
421 id1, true);
423 EXPECT_FALSE(MouseInCollection());
424 std::string id2 = AddNotification();
426 WaitForTransitionsDone();
427 views::WidgetDelegateView* toast2 = GetToast(id2);
428 EXPECT_TRUE(toast2 != NULL);
430 CloseAllToasts();
431 WaitForTransitionsDone();
435 } // namespace test
436 } // namespace message_center