eacc68077263adf9e73f8e58f0795024562bdc8d
[platform/framework/web/crosswalk.git] / src / ui / message_center / views / message_popup_collection_unittest.cc
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.
4
5 #include "ui/message_center/views/message_popup_collection.h"
6
7 #include <list>
8
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"
22
23 namespace message_center {
24 namespace test {
25
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();
43   }
44
45   virtual void TearDown() OVERRIDE {
46     collection_.reset();
47     MessageCenter::Shutdown();
48     views::ViewsTestBase::TearDown();
49   }
50
51  protected:
52   MessagePopupCollection* collection() { return collection_.get(); }
53
54   size_t GetToastCounts() {
55     return collection_->toasts_.size();
56   }
57
58   bool MouseInCollection() {
59     return collection_->latest_toast_entered_ != NULL;
60   }
61
62   bool IsToastShown(const std::string& id) {
63     views::Widget* widget = collection_->GetWidgetForTest(id);
64     return widget && widget->IsVisible();
65   }
66
67   views::Widget* GetWidget(const std::string& id) {
68     return collection_->GetWidgetForTest(id);
69   }
70
71   gfx::Rect GetWorkArea() {
72     return collection_->work_area_;
73   }
74
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;
81     }
82     return NULL;
83   }
84
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;
99   }
100
101   void PrepareForWait() { collection_->CreateRunLoopForTest(); }
102
103   // Assumes there is non-zero pending work.
104   void WaitForTransitionsDone() {
105     collection_->WaitForTest();
106     collection_->CreateRunLoopForTest();
107   }
108
109   void CloseAllToasts() {
110     // Assumes there is at least one toast to close.
111     EXPECT_TRUE(GetToastCounts() > 0);
112     MessageCenter::Get()->RemoveAllNotifications(false);
113   }
114
115   gfx::Rect GetToastRectAt(size_t index) {
116     return collection_->GetToastRectAt(index);
117   }
118
119  private:
120   scoped_ptr<MessagePopupCollection> collection_;
121   int id_;
122 };
123
124 TEST_F(MessagePopupCollectionTest, DismissOnClick) {
125
126   std::string id1 = AddNotification();
127   std::string id2 = AddNotification();
128   WaitForTransitionsDone();
129
130   EXPECT_EQ(2u, GetToastCounts());
131   EXPECT_TRUE(IsToastShown(id1));
132   EXPECT_TRUE(IsToastShown(id2));
133
134   MessageCenter::Get()->ClickOnNotification(id2);
135   WaitForTransitionsDone();
136
137   EXPECT_EQ(1u, GetToastCounts());
138   EXPECT_TRUE(IsToastShown(id1));
139   EXPECT_FALSE(IsToastShown(id2));
140
141   MessageCenter::Get()->ClickOnNotificationButton(id1, 0);
142   WaitForTransitionsDone();
143   EXPECT_EQ(0u, GetToastCounts());
144   EXPECT_FALSE(IsToastShown(id1));
145   EXPECT_FALSE(IsToastShown(id2));
146 }
147
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));
155
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));
160 }
161
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();
168
169   gfx::Rect r0 = GetToastRectAt(0);
170   gfx::Rect r1 = GetToastRectAt(1);
171   gfx::Rect r2 = GetToastRectAt(2);
172   gfx::Rect r3 = GetToastRectAt(3);
173
174   // 3 toasts are shown, equal size, vertical stack.
175   EXPECT_TRUE(IsToastShown(id0));
176   EXPECT_TRUE(IsToastShown(id1));
177   EXPECT_TRUE(IsToastShown(id2));
178
179   EXPECT_EQ(r0.width(), r1.width());
180   EXPECT_EQ(r1.width(), r2.width());
181
182   EXPECT_EQ(r0.height(), r1.height());
183   EXPECT_EQ(r1.height(), r2.height());
184
185   EXPECT_GT(r0.y(), r1.y());
186   EXPECT_GT(r1.y(), r2.y());
187
188   EXPECT_EQ(r0.x(), r1.x());
189   EXPECT_EQ(r1.x(), r2.x());
190
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());
195
196   CloseAllToasts();
197   EXPECT_EQ(0u, GetToastCounts());
198 }
199
200 TEST_F(MessagePopupCollectionTest, DefaultPositioningWithRightTaskbar) {
201   // If taskbar is on the right we show the toasts bottom to top as usual.
202
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();
209
210   gfx::Rect r0 = GetToastRectAt(0);
211   gfx::Rect r1 = GetToastRectAt(1);
212
213   // 2 toasts are shown, equal size, vertical stack.
214   EXPECT_TRUE(IsToastShown(id0));
215   EXPECT_TRUE(IsToastShown(id1));
216
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());
221
222   CloseAllToasts();
223   EXPECT_EQ(0u, GetToastCounts());
224
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.
228 }
229
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();
237
238   gfx::Rect r0 = GetToastRectAt(0);
239   gfx::Rect r1 = GetToastRectAt(1);
240
241   // 2 toasts are shown, equal size, vertical stack.
242   EXPECT_TRUE(IsToastShown(id0));
243   EXPECT_TRUE(IsToastShown(id1));
244
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());
249
250   CloseAllToasts();
251   EXPECT_EQ(0u, GetToastCounts());
252
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.
256 }
257
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.
261
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();
268
269   gfx::Rect r0 = GetToastRectAt(0);
270   gfx::Rect r1 = GetToastRectAt(1);
271
272   // 2 toasts are shown, equal size, vertical stack.
273   EXPECT_TRUE(IsToastShown(id0));
274   EXPECT_TRUE(IsToastShown(id1));
275
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());
280
281   CloseAllToasts();
282   EXPECT_EQ(0u, GetToastCounts());
283
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.
287 }
288
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.
292
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();
299
300   gfx::Rect r0 = GetToastRectAt(0);
301   gfx::Rect r1 = GetToastRectAt(1);
302
303   // 2 toasts are shown, equal size, vertical stack.
304   EXPECT_TRUE(IsToastShown(id0));
305   EXPECT_TRUE(IsToastShown(id1));
306
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());
311
312   CloseAllToasts();
313   EXPECT_EQ(0u, GetToastCounts());
314
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.
318 }
319
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();
327
328   gfx::Rect r0 = GetToastRectAt(0);
329   gfx::Rect r1 = GetToastRectAt(1);
330
331   // 2 toasts are shown, equal size, vertical stack.
332   EXPECT_TRUE(IsToastShown(id0));
333   EXPECT_TRUE(IsToastShown(id1));
334
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());
339
340   // Ensure that toasts are on the left.
341   EXPECT_LT(r1.x(), GetWorkArea().CenterPoint().x());
342
343   CloseAllToasts();
344   EXPECT_EQ(0u, GetToastCounts());
345
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.
349 }
350
351 TEST_F(MessagePopupCollectionTest, DetectMouseHover) {
352   std::string id0 = AddNotification();
353   std::string id1 = AddNotification();
354   WaitForTransitionsDone();
355
356   views::WidgetDelegateView* toast0 = GetToast(id0);
357   EXPECT_TRUE(toast0 != NULL);
358   views::WidgetDelegateView* toast1 = GetToast(id1);
359   EXPECT_TRUE(toast1 != NULL);
360
361   ui::MouseEvent event(ui::ET_MOUSE_MOVED, gfx::Point(), gfx::Point(), 0, 0);
362
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());
372
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());
382 }
383
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();
390
391   views::WidgetDelegateView* toast0 = GetToast(id0);
392   EXPECT_TRUE(toast0 != NULL);
393   views::WidgetDelegateView* toast1 = GetToast(id1);
394   ASSERT_TRUE(toast1 != NULL);
395
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);
400
401   EXPECT_FALSE(MouseInCollection());
402   std::string id2 = AddNotification();
403
404   WaitForTransitionsDone();
405   views::WidgetDelegateView* toast2 = GetToast(id2);
406   EXPECT_TRUE(toast2 != NULL);
407 }
408
409
410 }  // namespace test
411 }  // namespace message_center