Upstream version 9.38.198.0
[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/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"
23
24 namespace message_center {
25 namespace test {
26
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();
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   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();
78   }
79
80   gfx::Rect GetWorkArea() {
81     return alignment_delegate_->work_area_;
82   }
83
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;
90     }
91     return NULL;
92   }
93
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;
108   }
109
110   void PrepareForWait() { collection_->CreateRunLoopForTest(); }
111
112   // Assumes there is non-zero pending work.
113   void WaitForTransitionsDone() {
114     collection_->WaitForTest();
115     collection_->CreateRunLoopForTest();
116   }
117
118   void CloseAllToasts() {
119     // Assumes there is at least one toast to close.
120     EXPECT_TRUE(GetToastCounts() > 0);
121     MessageCenter::Get()->RemoveAllNotifications(false);
122   }
123
124   gfx::Rect GetToastRectAt(size_t index) {
125     return collection_->GetToastRectAt(index);
126   }
127
128  private:
129   scoped_ptr<MessagePopupCollection> collection_;
130   scoped_ptr<DesktopPopupAlignmentDelegate> alignment_delegate_;
131   int id_;
132 };
133
134 TEST_F(MessagePopupCollectionTest, DismissOnClick) {
135
136   std::string id1 = AddNotification();
137   std::string id2 = AddNotification();
138   WaitForTransitionsDone();
139
140   EXPECT_EQ(2u, GetToastCounts());
141   EXPECT_TRUE(IsToastShown(id1));
142   EXPECT_TRUE(IsToastShown(id2));
143
144   MessageCenter::Get()->ClickOnNotification(id2);
145   WaitForTransitionsDone();
146
147   EXPECT_EQ(1u, GetToastCounts());
148   EXPECT_TRUE(IsToastShown(id1));
149   EXPECT_FALSE(IsToastShown(id2));
150
151   MessageCenter::Get()->ClickOnNotificationButton(id1, 0);
152   WaitForTransitionsDone();
153   EXPECT_EQ(0u, GetToastCounts());
154   EXPECT_FALSE(IsToastShown(id1));
155   EXPECT_FALSE(IsToastShown(id2));
156 }
157
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));
165
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));
170 }
171
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();
178
179   gfx::Rect r0 = GetToastRectAt(0);
180   gfx::Rect r1 = GetToastRectAt(1);
181   gfx::Rect r2 = GetToastRectAt(2);
182   gfx::Rect r3 = GetToastRectAt(3);
183
184   // 3 toasts are shown, equal size, vertical stack.
185   EXPECT_TRUE(IsToastShown(id0));
186   EXPECT_TRUE(IsToastShown(id1));
187   EXPECT_TRUE(IsToastShown(id2));
188
189   EXPECT_EQ(r0.width(), r1.width());
190   EXPECT_EQ(r1.width(), r2.width());
191
192   EXPECT_EQ(r0.height(), r1.height());
193   EXPECT_EQ(r1.height(), r2.height());
194
195   EXPECT_GT(r0.y(), r1.y());
196   EXPECT_GT(r1.y(), r2.y());
197
198   EXPECT_EQ(r0.x(), r1.x());
199   EXPECT_EQ(r1.x(), r2.x());
200
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());
205
206   CloseAllToasts();
207   EXPECT_EQ(0u, GetToastCounts());
208 }
209
210 TEST_F(MessagePopupCollectionTest, DefaultPositioningWithRightTaskbar) {
211   // If taskbar is on the right we show the toasts bottom to top as usual.
212
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();
219
220   gfx::Rect r0 = GetToastRectAt(0);
221   gfx::Rect r1 = GetToastRectAt(1);
222
223   // 2 toasts are shown, equal size, vertical stack.
224   EXPECT_TRUE(IsToastShown(id0));
225   EXPECT_TRUE(IsToastShown(id1));
226
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());
231
232   CloseAllToasts();
233   EXPECT_EQ(0u, GetToastCounts());
234
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.
238 }
239
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();
247
248   gfx::Rect r0 = GetToastRectAt(0);
249   gfx::Rect r1 = GetToastRectAt(1);
250
251   // 2 toasts are shown, equal size, vertical stack.
252   EXPECT_TRUE(IsToastShown(id0));
253   EXPECT_TRUE(IsToastShown(id1));
254
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());
259
260   CloseAllToasts();
261   EXPECT_EQ(0u, GetToastCounts());
262
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.
266 }
267
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.
271
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();
278
279   gfx::Rect r0 = GetToastRectAt(0);
280   gfx::Rect r1 = GetToastRectAt(1);
281
282   // 2 toasts are shown, equal size, vertical stack.
283   EXPECT_TRUE(IsToastShown(id0));
284   EXPECT_TRUE(IsToastShown(id1));
285
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());
290
291   CloseAllToasts();
292   EXPECT_EQ(0u, GetToastCounts());
293
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.
297 }
298
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.
302
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();
309
310   gfx::Rect r0 = GetToastRectAt(0);
311   gfx::Rect r1 = GetToastRectAt(1);
312
313   // 2 toasts are shown, equal size, vertical stack.
314   EXPECT_TRUE(IsToastShown(id0));
315   EXPECT_TRUE(IsToastShown(id1));
316
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());
321
322   CloseAllToasts();
323   EXPECT_EQ(0u, GetToastCounts());
324
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.
328 }
329
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();
337
338   gfx::Rect r0 = GetToastRectAt(0);
339   gfx::Rect r1 = GetToastRectAt(1);
340
341   // 2 toasts are shown, equal size, vertical stack.
342   EXPECT_TRUE(IsToastShown(id0));
343   EXPECT_TRUE(IsToastShown(id1));
344
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());
349
350   // Ensure that toasts are on the left.
351   EXPECT_LT(r1.x(), GetWorkArea().CenterPoint().x());
352
353   CloseAllToasts();
354   EXPECT_EQ(0u, GetToastCounts());
355
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.
359 }
360
361 TEST_F(MessagePopupCollectionTest, DetectMouseHover) {
362   std::string id0 = AddNotification();
363   std::string id1 = AddNotification();
364   WaitForTransitionsDone();
365
366   views::WidgetDelegateView* toast0 = GetToast(id0);
367   EXPECT_TRUE(toast0 != NULL);
368   views::WidgetDelegateView* toast1 = GetToast(id1);
369   EXPECT_TRUE(toast1 != NULL);
370
371   ui::MouseEvent event(ui::ET_MOUSE_MOVED, gfx::Point(), gfx::Point(), 0, 0);
372
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());
382
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());
392 }
393
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();
400
401   views::WidgetDelegateView* toast0 = GetToast(id0);
402   EXPECT_TRUE(toast0 != NULL);
403   views::WidgetDelegateView* toast1 = GetToast(id1);
404   ASSERT_TRUE(toast1 != NULL);
405
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);
410
411   EXPECT_FALSE(MouseInCollection());
412   std::string id2 = AddNotification();
413
414   WaitForTransitionsDone();
415   views::WidgetDelegateView* toast2 = GetToast(id2);
416   EXPECT_TRUE(toast2 != NULL);
417 }
418
419
420 }  // namespace test
421 }  // namespace message_center