- add sources.
[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     collection_.reset(new MessagePopupCollection(
32         GetContext(), MessageCenter::Get(), NULL, false));
33     // This size fits test machines resolution and also can keep a few toasts
34     // w/o ill effects of hitting the screen overflow. This allows us to assume
35     // and verify normal layout of the toast stack.
36     collection_->SetDisplayInfo(gfx::Rect(0, 0, 600, 390),
37                                 gfx::Rect(0, 0, 600, 400));  // Simulate a
38                                                              // taskbar at the
39                                                              // bottom.
40     id_ = 0;
41   }
42
43   virtual void TearDown() OVERRIDE {
44     collection_->CloseAllWidgets();
45     collection_.reset();
46     MessageCenter::Shutdown();
47     views::ViewsTestBase::TearDown();
48   }
49
50  protected:
51   MessagePopupCollection* collection() { return collection_.get(); }
52
53   size_t GetToastCounts() {
54     return collection_->toasts_.size();
55   }
56
57   bool MouseInCollection() {
58     return collection_->latest_toast_entered_ != NULL;
59   }
60
61   bool IsToastShown(const std::string& id) {
62     views::Widget* widget = collection_->GetWidgetForTest(id);
63     return widget && widget->IsVisible();
64   }
65
66   views::Widget* GetWidget(const std::string& id) {
67     return collection_->GetWidgetForTest(id);
68   }
69
70   gfx::Rect GetWorkArea() {
71     return collection_->work_area_;
72   }
73
74   ToastContentsView* GetToast(const std::string& id) {
75     for (MessagePopupCollection::Toasts::iterator iter =
76              collection_->toasts_.begin();
77          iter != collection_->toasts_.end(); ++iter) {
78       if ((*iter)->id() == id)
79         return *iter;
80     }
81     return NULL;
82   }
83
84   std::string AddNotification() {
85     std::string id = base::IntToString(id_++);
86     scoped_ptr<Notification> notification(
87         new Notification(NOTIFICATION_TYPE_BASE_FORMAT,
88                          id,
89                          UTF8ToUTF16("test title"),
90                          UTF8ToUTF16("test message"),
91                          gfx::Image(),
92                          string16() /* display_source */,
93                          NotifierId(),
94                          message_center::RichNotificationData(),
95                          NULL /* delegate */));
96     MessageCenter::Get()->AddNotification(notification.Pass());
97     return id;
98   }
99
100   // Assumes there is non-zero pending work.
101   void WaitForTransitionsDone() {
102     collection_->RunLoopForTest();
103   }
104
105   void CloseAllToastsAndWait() {
106     // Assumes there is at least one toast to close.
107     EXPECT_TRUE(GetToastCounts() > 0);
108     MessageCenter::Get()->RemoveAllNotifications(false);
109     WaitForTransitionsDone();
110   }
111
112   gfx::Rect GetToastRectAt(size_t index) {
113     return collection_->GetToastRectAt(index);
114   }
115
116  private:
117   scoped_ptr<MessagePopupCollection> collection_;
118   int id_;
119 };
120
121 TEST_F(MessagePopupCollectionTest, DismissOnClick) {
122   std::string id1 = AddNotification();
123   std::string id2 = AddNotification();
124   WaitForTransitionsDone();
125   EXPECT_EQ(2u, GetToastCounts());
126   EXPECT_TRUE(IsToastShown(id1));
127   EXPECT_TRUE(IsToastShown(id2));
128
129   MessageCenter::Get()->ClickOnNotification(id2);
130   WaitForTransitionsDone();
131   EXPECT_EQ(1u, GetToastCounts());
132   EXPECT_TRUE(IsToastShown(id1));
133   EXPECT_FALSE(IsToastShown(id2));
134
135   MessageCenter::Get()->ClickOnNotificationButton(id1, 0);
136   WaitForTransitionsDone();
137   EXPECT_EQ(0u, GetToastCounts());
138   EXPECT_FALSE(IsToastShown(id1));
139   EXPECT_FALSE(IsToastShown(id2));
140 }
141
142 TEST_F(MessagePopupCollectionTest, ShutdownDuringShowing) {
143   std::string id1 = AddNotification();
144   std::string id2 = AddNotification();
145   WaitForTransitionsDone();
146   EXPECT_EQ(2u, GetToastCounts());
147   EXPECT_TRUE(IsToastShown(id1));
148   EXPECT_TRUE(IsToastShown(id2));
149
150   // Finish without cleanup of notifications, which may cause use-after-free.
151   // See crbug.com/236448
152   GetWidget(id1)->CloseNow();
153   collection()->OnMouseExited(GetToast(id2));
154 }
155
156 TEST_F(MessagePopupCollectionTest, DefaultPositioning) {
157   std::string id0 = AddNotification();
158   std::string id1 = AddNotification();
159   std::string id2 = AddNotification();
160   std::string id3 = AddNotification();
161   WaitForTransitionsDone();
162
163   gfx::Rect r0 = GetToastRectAt(0);
164   gfx::Rect r1 = GetToastRectAt(1);
165   gfx::Rect r2 = GetToastRectAt(2);
166   gfx::Rect r3 = GetToastRectAt(3);
167
168   // 3 toasts are shown, equal size, vertical stack.
169   EXPECT_TRUE(IsToastShown(id0));
170   EXPECT_TRUE(IsToastShown(id1));
171   EXPECT_TRUE(IsToastShown(id2));
172
173   EXPECT_EQ(r0.width(), r1.width());
174   EXPECT_EQ(r1.width(), r2.width());
175
176   EXPECT_EQ(r0.height(), r1.height());
177   EXPECT_EQ(r1.height(), r2.height());
178
179   EXPECT_GT(r0.y(), r1.y());
180   EXPECT_GT(r1.y(), r2.y());
181
182   EXPECT_EQ(r0.x(), r1.x());
183   EXPECT_EQ(r1.x(), r2.x());
184
185   // The 4th toast is not shown yet.
186   EXPECT_FALSE(IsToastShown(id3));
187   EXPECT_EQ(0, r3.width());
188   EXPECT_EQ(0, r3.height());
189
190   CloseAllToastsAndWait();
191   EXPECT_EQ(0u, GetToastCounts());
192 }
193
194 TEST_F(MessagePopupCollectionTest, DefaultPositioningWithRightTaskbar) {
195   // If taskbar is on the right we show the toasts bottom to top as usual.
196
197   // Simulate a taskbar at the right.
198   collection()->SetDisplayInfo(gfx::Rect(0, 0, 590, 400),   // Work-area.
199                                gfx::Rect(0, 0, 600, 400));  // Display-bounds.
200   std::string id0 = AddNotification();
201   std::string id1 = AddNotification();
202   WaitForTransitionsDone();
203
204   gfx::Rect r0 = GetToastRectAt(0);
205   gfx::Rect r1 = GetToastRectAt(1);
206
207   // 2 toasts are shown, equal size, vertical stack.
208   EXPECT_TRUE(IsToastShown(id0));
209   EXPECT_TRUE(IsToastShown(id1));
210
211   EXPECT_EQ(r0.width(), r1.width());
212   EXPECT_EQ(r0.height(), r1.height());
213   EXPECT_GT(r0.y(), r1.y());
214   EXPECT_EQ(r0.x(), r1.x());
215
216   CloseAllToastsAndWait();
217   EXPECT_EQ(0u, GetToastCounts());
218
219   // Restore simulated taskbar position to bottom.
220   collection()->SetDisplayInfo(gfx::Rect(0, 0, 600, 390),  // Work-area.
221                                gfx::Rect(0, 0, 600, 400)); // Display-bounds.
222 }
223
224 TEST_F(MessagePopupCollectionTest, TopDownPositioningWithTopTaskbar) {
225   // Simulate a taskbar at the top.
226   collection()->SetDisplayInfo(gfx::Rect(0, 10, 600, 390),  // Work-area.
227                                gfx::Rect(0, 0, 600, 400));  // Display-bounds.
228   std::string id0 = AddNotification();
229   std::string id1 = AddNotification();
230   WaitForTransitionsDone();
231
232   gfx::Rect r0 = GetToastRectAt(0);
233   gfx::Rect r1 = GetToastRectAt(1);
234
235   // 2 toasts are shown, equal size, vertical stack.
236   EXPECT_TRUE(IsToastShown(id0));
237   EXPECT_TRUE(IsToastShown(id1));
238
239   EXPECT_EQ(r0.width(), r1.width());
240   EXPECT_EQ(r0.height(), r1.height());
241   EXPECT_LT(r0.y(), r1.y());
242   EXPECT_EQ(r0.x(), r1.x());
243
244   CloseAllToastsAndWait();
245   EXPECT_EQ(0u, GetToastCounts());
246
247   // Restore simulated taskbar position to bottom.
248   collection()->SetDisplayInfo(gfx::Rect(0, 0, 600, 390),   // Work-area.
249                                gfx::Rect(0, 0, 600, 400));  // Display-bounds.
250 }
251
252 TEST_F(MessagePopupCollectionTest, TopDownPositioningWithLeftAndTopTaskbar) {
253   // If there "seems" to be a taskbar on left and top (like in Unity), it is
254   // assumed that the actual taskbar is the top one.
255
256   // Simulate a taskbar at the top and left.
257   collection()->SetDisplayInfo(gfx::Rect(10, 10, 590, 390),  // Work-area.
258                                gfx::Rect(0, 0, 600, 400));   // Display-bounds.
259   std::string id0 = AddNotification();
260   std::string id1 = AddNotification();
261   WaitForTransitionsDone();
262
263   gfx::Rect r0 = GetToastRectAt(0);
264   gfx::Rect r1 = GetToastRectAt(1);
265
266   // 2 toasts are shown, equal size, vertical stack.
267   EXPECT_TRUE(IsToastShown(id0));
268   EXPECT_TRUE(IsToastShown(id1));
269
270   EXPECT_EQ(r0.width(), r1.width());
271   EXPECT_EQ(r0.height(), r1.height());
272   EXPECT_LT(r0.y(), r1.y());
273   EXPECT_EQ(r0.x(), r1.x());
274
275   CloseAllToastsAndWait();
276   EXPECT_EQ(0u, GetToastCounts());
277
278   // Restore simulated taskbar position to bottom.
279   collection()->SetDisplayInfo(gfx::Rect(0, 0, 600, 390),   // Work-area.
280                                gfx::Rect(0, 0, 600, 400));  // Display-bounds.
281 }
282
283 TEST_F(MessagePopupCollectionTest, TopDownPositioningWithBottomAndTopTaskbar) {
284   // If there "seems" to be a taskbar on bottom and top (like in Gnome), it is
285   // assumed that the actual taskbar is the top one.
286
287   // Simulate a taskbar at the top and bottom.
288   collection()->SetDisplayInfo(gfx::Rect(0, 10, 580, 400),  // Work-area.
289                                gfx::Rect(0, 0, 600, 400));  // Display-bounds.
290   std::string id0 = AddNotification();
291   std::string id1 = AddNotification();
292   WaitForTransitionsDone();
293
294   gfx::Rect r0 = GetToastRectAt(0);
295   gfx::Rect r1 = GetToastRectAt(1);
296
297   // 2 toasts are shown, equal size, vertical stack.
298   EXPECT_TRUE(IsToastShown(id0));
299   EXPECT_TRUE(IsToastShown(id1));
300
301   EXPECT_EQ(r0.width(), r1.width());
302   EXPECT_EQ(r0.height(), r1.height());
303   EXPECT_LT(r0.y(), r1.y());
304   EXPECT_EQ(r0.x(), r1.x());
305
306   CloseAllToastsAndWait();
307   EXPECT_EQ(0u, GetToastCounts());
308
309   // Restore simulated taskbar position to bottom.
310   collection()->SetDisplayInfo(gfx::Rect(0, 0, 600, 390),   // Work-area.
311                                gfx::Rect(0, 0, 600, 400));  // Display-bounds.
312 }
313
314 TEST_F(MessagePopupCollectionTest, LeftPositioningWithLeftTaskbar) {
315   // Simulate a taskbar at the left.
316   collection()->SetDisplayInfo(gfx::Rect(10, 0, 590, 400),  // Work-area.
317                                gfx::Rect(0, 0, 600, 400));  // Display-bounds.
318   std::string id0 = AddNotification();
319   std::string id1 = AddNotification();
320   WaitForTransitionsDone();
321
322   gfx::Rect r0 = GetToastRectAt(0);
323   gfx::Rect r1 = GetToastRectAt(1);
324
325   // 2 toasts are shown, equal size, vertical stack.
326   EXPECT_TRUE(IsToastShown(id0));
327   EXPECT_TRUE(IsToastShown(id1));
328
329   EXPECT_EQ(r0.width(), r1.width());
330   EXPECT_EQ(r0.height(), r1.height());
331   EXPECT_GT(r0.y(), r1.y());
332   EXPECT_EQ(r0.x(), r1.x());
333
334   // Ensure that toasts are on the left.
335   EXPECT_LT(r1.x(), GetWorkArea().CenterPoint().x());
336
337   CloseAllToastsAndWait();
338   EXPECT_EQ(0u, GetToastCounts());
339
340   // Restore simulated taskbar position to bottom.
341   collection()->SetDisplayInfo(gfx::Rect(0, 0, 600, 390),   // Work-area.
342                                gfx::Rect(0, 0, 600, 400));  // Display-bounds.
343 }
344
345 TEST_F(MessagePopupCollectionTest, DetectMouseHover) {
346   std::string id0 = AddNotification();
347   std::string id1 = AddNotification();
348   WaitForTransitionsDone();
349
350   views::WidgetDelegateView* toast0 = GetToast(id0);
351   EXPECT_TRUE(toast0 != NULL);
352   views::WidgetDelegateView* toast1 = GetToast(id1);
353   EXPECT_TRUE(toast1 != NULL);
354
355   ui::MouseEvent event(ui::ET_MOUSE_MOVED, gfx::Point(), gfx::Point(), 0);
356
357   // Test that mouse detection logic works in presence of out-of-order events.
358   toast0->OnMouseEntered(event);
359   EXPECT_TRUE(MouseInCollection());
360   toast1->OnMouseEntered(event);
361   EXPECT_TRUE(MouseInCollection());
362   toast0->OnMouseExited(event);
363   EXPECT_TRUE(MouseInCollection());
364   toast1->OnMouseExited(event);
365   EXPECT_FALSE(MouseInCollection());
366
367   // Test that mouse detection logic works in presence of WindowClosing events.
368   toast0->OnMouseEntered(event);
369   EXPECT_TRUE(MouseInCollection());
370   toast1->OnMouseEntered(event);
371   EXPECT_TRUE(MouseInCollection());
372   toast0->WindowClosing();
373   EXPECT_TRUE(MouseInCollection());
374   toast1->WindowClosing();
375   EXPECT_FALSE(MouseInCollection());
376 }
377
378 // TODO(dimich): Test repositioning - both normal one and when user is closing
379 // the toasts.
380 TEST_F(MessagePopupCollectionTest, DetectMouseHoverWithUserClose) {
381   std::string id0 = AddNotification();
382   std::string id1 = AddNotification();
383   WaitForTransitionsDone();
384
385   views::WidgetDelegateView* toast0 = GetToast(id0);
386   EXPECT_TRUE(toast0 != NULL);
387   views::WidgetDelegateView* toast1 = GetToast(id1);
388   ASSERT_TRUE(toast1 != NULL);
389
390   ui::MouseEvent event(ui::ET_MOUSE_MOVED, gfx::Point(), gfx::Point(), 0);
391   toast1->OnMouseEntered(event);
392   static_cast<MessageCenterObserver*>(collection())->OnNotificationRemoved(
393       id1, true);
394
395   EXPECT_FALSE(MouseInCollection());
396   std::string id2 = AddNotification();
397
398   WaitForTransitionsDone();
399   views::WidgetDelegateView* toast2 = GetToast(id2);
400   EXPECT_TRUE(toast2 != NULL);
401 }
402
403
404 }  // namespace test
405 }  // namespace message_center